diff --git a/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONException.java b/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONException.java new file mode 100644 index 0000000..e8c8d08 --- /dev/null +++ b/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONException.java @@ -0,0 +1,12 @@ +package cz.cvut.fel.aic.graphimporter.geojson; + +import org.json.simple.JSONObject; + +/** + * @author Zdenek Bousa + */ +class GeoJSONException extends Exception { + GeoJSONException(JSONObject properties, String key) { + super("Missing key: \'" + key + "\' in GeoJSON properties: " + properties); + } +} diff --git a/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONParser.java b/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONParser.java new file mode 100644 index 0000000..8f3a7db --- /dev/null +++ b/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONParser.java @@ -0,0 +1,170 @@ +package cz.cvut.fel.aic.graphimporter.geojson; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.util.*; + +/** + * @author Zdenek Bousa + */ +public class GeoJSONParser { + static float tryParseFloat(JSONObject properties, String key, float defaultValue) { + float value; + try { + value = tryParseFloat(properties, key); + } catch (GeoJSONException e) { + value = defaultValue; + } + return value; + } + + static float tryParseFloat(JSONObject properties, String key) throws GeoJSONException { + float value; + Object valueObject = properties.get(key); + if (valueObject instanceof Number) { + value = ((Number) valueObject).floatValue(); + } else if (valueObject instanceof String) { + String valueString = (String) valueObject; + value = Float.parseFloat(valueString); + } else { + throw new GeoJSONException(properties, key); + } + return value; + } + + static Long tryParseLong(JSONObject properties, String key, long defaultValue) { + Long value; + try { + value = tryParseLong(properties, key); + } catch (GeoJSONException e) { + value = defaultValue; + } + return value; + } + + static Long tryParseLong(JSONObject properties, String key) throws GeoJSONException { + Object valueObject = properties.get(key); + Long value; + if (valueObject instanceof Number) { + value = ((Number) valueObject).longValue(); + } else if (valueObject instanceof String) { + String valueString = (String) valueObject; + value = Long.parseLong(valueString); + } else { + throw new GeoJSONException(properties, key); + } + return value; + } + + static int tryParseInt(JSONObject properties, String key, int defaultValue) { + int value; + try { + value = tryParseInt(properties, key); + } catch (GeoJSONException e) { + value = defaultValue; + } + return value; + } + + static int tryParseInt(JSONObject properties, String key) throws GeoJSONException { + int value; + Object valueObject = properties.get(key); + if (valueObject instanceof Number) { + value = ((Number) valueObject).intValue(); + } else if (valueObject instanceof String) { + String valueString = (String) valueObject; + value = Integer.parseInt(valueString); + } else { + throw new GeoJSONException(properties, key); + } + return value; + } + + + static Map tryParseDict(JSONObject properties, String key) throws GeoJSONException { + Map map = null; + JSONObject value; + if (key != null) { + if (properties != null) { + value = (JSONObject) properties.get(key); + } else { + return null; + } + } else { + value = properties; + } + if (value != null) { + map = getMap(value); + } + return map; + } + + static List tryParseList(JSONObject properties, String key) throws GeoJSONException { + JSONArray m = (JSONArray) properties.get(key); + if (m == null){ + return null; + } + + List list = new ArrayList<>(); + for (Object aM : m) { + if (aM instanceof JSONObject) { + list.add((JSONObject) aM); + } else { + throw new GeoJSONException(properties, key); + } + } + return list; + } + + static JSONObject parseStringToJSON(String tagsString) { + if (tagsString == null) return null; + tagsString = "{" + tagsString.replaceAll("=>", ":") + "}"; + JSONObject json; + JSONParser parser = new JSONParser(); + try { + json = (JSONObject) parser.parse(tagsString); + } catch (ParseException e) { + e.printStackTrace(); + json = null; + } + return json; + } + + private static Map getMap(JSONObject object) throws GeoJSONException { + Map map = new HashMap<>(); + + Set keys = object.keySet(); + for (Object keyO : keys) { + Object value = object.get(keyO); + + if (value instanceof JSONArray) { + value = getList((JSONArray) value); + } else if (value instanceof JSONObject) { + value = getMap((JSONObject) value); + } + + if (keyO instanceof String) { + map.put((String) keyO, value); + } else { + return null; + } + } + return map; + } + + private static List getList(JSONArray array) throws GeoJSONException { + List list = new ArrayList<>(); + for (Object value : array) { + if (value instanceof JSONArray) { + value = getList((JSONArray) value); + } else if (value instanceof JSONObject) { + value = getMap((JSONObject) value); + } + list.add(value); + } + return list; + } +} diff --git a/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONReader.java b/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONReader.java index 8df8eaf..347c7a6 100644 --- a/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONReader.java +++ b/src/main/java/cz/cvut/fel/aic/graphimporter/geojson/GeoJSONReader.java @@ -39,6 +39,8 @@ import java.io.IOException; import java.util.*; +import static cz.cvut.fel.aic.graphimporter.geojson.GeoJSONParser.*; + public class GeoJSONReader extends Importer { private static final Logger LOGGER = Logger.getLogger(GeoJSONReader.class); @@ -47,29 +49,55 @@ public class GeoJSONReader extends Importer { private final Transformer projection; private JSONArray features; - private final File geoJsonFile; - + private final File geoJsonEdgeFile; private final File geoJsonNodeFile; - private boolean isBothWayOverride = false; - - protected final TmpGraphBuilder builder; + private final TmpGraphBuilder builder; - public GeoJSONReader(String geoJsonFile, String geoJsonNodeFile, Transformer projection) { - this(new File(geoJsonFile), new File(geoJsonNodeFile), projection); + public GeoJSONReader(String geoJsonEdgeFile, String geoJsonNodeFile, Transformer projection) { + this(new File(geoJsonEdgeFile), new File(geoJsonNodeFile), projection); } - public GeoJSONReader(File geoJsonFile, File geoJsonNodeFile, Transformer projection) { + public GeoJSONReader(File geoJsonEdgeFile, File geoJsonNodeFile, Transformer projection) { this.projection = projection; - this.geoJsonFile = geoJsonFile; + this.geoJsonEdgeFile = geoJsonEdgeFile; this.geoJsonNodeFile = geoJsonNodeFile; this.nodes = new HashMap<>(); - builder = new TmpGraphBuilder<>(); } + @Override + public String getSerializationName() { + return geoJsonEdgeFile.getName() + ".ser"; + } + + @Override + public TmpGraphBuilder loadGraph() { + LOGGER.info("Parsing of geojson started..."); + + long t1 = System.currentTimeMillis(); + + try (FileReader fr = new FileReader(geoJsonNodeFile)) { + parseFeatures(fr); + processFeatures(); + } catch (IOException | ParseException e) { + throw new IllegalStateException("GeoJSON Nodes can't be parsed.", e); + } + + try (FileReader fr = new FileReader(geoJsonEdgeFile)) { + parseFeatures(fr); + processFeatures(); + } catch (IOException | ParseException e) { + throw new IllegalStateException("GeoJSON Edges can't be parsed.", e); + } + + + long t2 = System.currentTimeMillis(); + LOGGER.info("Parsing of GeoJSON finished in " + (t2 - t1) + "ms"); + return builder; + } private void processFeatures() { for (Object feature : features) { @@ -78,165 +106,54 @@ private void processFeatures() { } - int addNode(GPSLocation location, long sourceId) { + private int addNode(GPSLocation location, long sourceId) { InternalNodeBuilder nodeBuilder = new InternalNodeBuilder(builder.getNodeCount(), sourceId, location); builder.addNode(nodeBuilder); return nodeBuilder.tmpId; } - - void parseFeature(JSONObject feature) { - JSONObject properties = (JSONObject) feature.get("properties"); - JSONObject geometry = (JSONObject) feature.get("geometry"); - JSONArray coordinates = (JSONArray) geometry.get("coordinates"); - - String geometryType = (String) geometry.get("type"); - Boolean isOneWay = true; - if (properties.containsKey("oneway")) { - isOneWay = ((String) properties.get("oneway")).equalsIgnoreCase("yes"); - } - if (geometryType.equals("LineString")) { - JSONArray fromLatLon = (JSONArray) coordinates.get(0); - JSONArray toLatlon = (JSONArray) coordinates.get(coordinates.size() - 1); - int fromId = getOrCreateNode(fromLatLon, properties); - int toId = getOrCreateNode(toLatlon, properties); - addEdge(fromId, toId, properties, coordinates); - if (!isOneWay || isBothWayOverride) { - addEdge(toId, fromId, properties, coordinates); - } - } else if (geometryType.equals("Point")) { - int fromId = getOrCreateNode(coordinates, properties); - } - - - } - - private JSONObject parseStringToJSON(String tagsString) { - if (tagsString == null) return null; - tagsString = "{" + tagsString.replaceAll("=>", ":") + "}"; - JSONObject json; - JSONParser parser = new JSONParser(); + private void addEdge(int fromId, int toId, JSONObject properties, JSONArray coordinates) { try { - json = (JSONObject) parser.parse(tagsString); - } catch (ParseException e) { - e.printStackTrace(); - json = null; - } - return json; - } - + //in case of unknown ID, use negative negative builder edge count + int uniqueWayId = tryParseInt(properties, "id", -builder.getEdgeCount()); + int oppositeWayUniqueId = tryParseInt(properties, "id_opposite", -1); - void addEdge(int fromId, int toId, JSONObject properties, JSONArray coordinates) { - Long osmId = null; - try { - osmId = tryParseLong(properties, "id"); - int uniqueWayId = builder.getEdgeCount(); - int oppositeWayUniqueId = -1; int length = tryParseInt(properties, "length"); -// int length = GPSLocationTools.computeDistance(graphBuilder.getNode(fromId).location, graphBuilder.getNode(toId).location); + Set modeOfTransports = new HashSet<>(); modeOfTransports.add(TransportMode.CAR); + float allowedMaxSpeedInMpS = tryParseFloat(properties, "speed") / 3.6f; - int lanesCount = tryParseInt(properties, "lanes"); + int lanesCount = tryParseInt(properties, "lanes", 1); + + List> lanes = tryParseLanes(properties, "turn:lanes:id"); + List coordinateList = new ArrayList<>(); - for (int i = 0; i < coordinates.size(); i++) { - coordinateList.add(getGpsLocation((JSONArray) coordinates.get(i),0)); + for (Object coordinate : coordinates) { + coordinateList.add(getGpsLocation((JSONArray) coordinate, 0)); } - InternalEdgeBuilder edgeBuilder = new InternalEdgeBuilder(fromId, toId, osmId, uniqueWayId, oppositeWayUniqueId, - length, modeOfTransports, allowedMaxSpeedInMpS, lanesCount, coordinateList); + + // Build edge + InternalEdgeBuilder edgeBuilder = new InternalEdgeBuilder(fromId, toId, uniqueWayId, oppositeWayUniqueId, + length, modeOfTransports, allowedMaxSpeedInMpS, lanesCount, coordinateList, lanes); builder.addEdge(edgeBuilder); + } catch (GeoJSONException e) { e.printStackTrace(); System.exit(1); } } - private float tryParseFloat(JSONObject properties, String key, float defaultValue) { - float value; - try { - value = tryParseFloat(properties, key); - } catch (GeoJSONException e) { - value = defaultValue; - } - return value; - } - - private float tryParseFloat(JSONObject properties, String key) throws GeoJSONException { - float value; - Object valueObject = properties.get(key); - if (valueObject instanceof Number) { - value = ((Number) valueObject).floatValue(); - } else if (valueObject instanceof String) { - String valueString = (String) valueObject; - value = Float.parseFloat(valueString); - } else { - throw new GeoJSONException(properties, key); - } - return value; - } - - private Long tryParseLong(JSONObject properties, String key, long defaultValue) { - Long value; - try { - value = tryParseLong(properties, key); - } catch (GeoJSONException e) { - value = defaultValue; - } - return value; - } - - private Long tryParseLong(JSONObject properties, String key) throws GeoJSONException { - Object valueObject = properties.get(key); - Long value; - if (valueObject instanceof Number) { - value = ((Number) valueObject).longValue(); - } else if (valueObject instanceof String) { - String valueString = (String) valueObject; - value = Long.parseLong(valueString); - } else { - throw new GeoJSONException(properties, key); - } - return value; - } - - private int tryParseInt(JSONObject properties, String key, int defaultValue) { - int value; - try { - value = tryParseInt(properties, key); - } catch (GeoJSONException e) { - value = defaultValue; - } - return value; - } - - private int tryParseInt(JSONObject properties, String key) throws GeoJSONException { - int value; - Object valueObject = properties.get(key); - if (valueObject instanceof Number) { - value = ((Number) valueObject).intValue(); - } else if (valueObject instanceof String) { - String valueString = (String) valueObject; - value = Integer.parseInt(valueString); - } else { - throw new GeoJSONException(properties, key); - } - return value; - } - - private int getOrCreateNode(JSONArray latLon, JSONObject properties) { String nodesIdKey = "node_id"; int elevation = 0; String coordinatesString = latLon.toString(); - long sourceId = tryParseLong(properties, nodesIdKey, -1); - if (!nodes.containsKey(coordinatesString)) { GPSLocation location = getGpsLocation(latLon, elevation); -// System.out.println(location +" "+location.lonProjected+" "+location.latProjected); addNode(location, sourceId); int id = builder.getIntIdForSourceId(sourceId); nodes.put(coordinatesString, id); @@ -250,64 +167,38 @@ private GPSLocation getGpsLocation(JSONArray latlonArray, int elevation) { return GPSLocationTools.createGPSLocation(lat, lon, Math.round(elevation), projection); } - public void setIsBothWayOverride(boolean isBothWayOverride) { - this.isBothWayOverride = isBothWayOverride; - } - -// public static void main(String[] args) { -// File geoJSONFile = new File("/home/martin/projects/skoda/skoda/osm_lines.geojson"); -// Transformer projection = new Transformer(2065); -// TmpGraphBuilder builder = new TmpGraphBuilder(); -// GeoJSONReader reader = null; -// try (FileReader fr = new FileReader((geoJSONFile))) { -// reader = new GeoJSONReader(fr, projection,new HashMap<>()); -// } catch (IOException | ParseException e) { -// e.printStackTrace(); -// } -// TmpGraphBuilder graphBuilder = null; -// -// graphBuilder = reader.parseGraphFeatures(builder); -// -// assert graphBuilder != null; -// Graph graph = graphBuilder.createGraph(); -// System.out.println(graph); -// -// -// } - - @Override - public String getSerializationName() { - return geoJsonFile.getName() + ".ser"; - } - - @Override - public TmpGraphBuilder loadGraph() { - parseGEOJSON(); - return builder; - } - - protected void parseGEOJSON() { - LOGGER.info("Parsing of geojson started..."); - - long t1 = System.currentTimeMillis(); - - try (FileReader fr = new FileReader(geoJsonNodeFile)) { - parseFeatures(fr); - processFeatures(); - } catch (IOException | ParseException e) { - throw new IllegalStateException("GeoJSON Nodes can't be parsed.", e); - } - - try (FileReader fr = new FileReader(geoJsonFile)) { - parseFeatures(fr); - processFeatures(); - } catch (IOException | ParseException e) { - throw new IllegalStateException("GeoJSON Edges can't be parsed.", e); + private List> tryParseLanes(JSONObject properties, String key) { + Map data; + List> lanes = new ArrayList<>(); + try { + List list = tryParseList(properties, key); + if (list == null) { + return null; + } + for (JSONObject l : list) { + Map lane = new HashMap<>(); + data = tryParseDict(l, null); + for (Map.Entry entry : data.entrySet()) { + String keyD = entry.getKey(); + Object valueD = entry.getValue(); + Integer valueN = -1; + + if (valueD instanceof Integer) { + valueN = (Integer) valueD; + } else if (valueD instanceof Long) { + Long val = (Long) valueD; + valueN = val.intValue(); + } + + lane.put(keyD, valueN); + } + lanes.add(lane); + } + } catch (GeoJSONException e) { + LOGGER.warn(e); + return null; } - - - long t2 = System.currentTimeMillis(); - LOGGER.info("Parsing of GeoJSON finished in " + (t2 - t1) + "ms"); + return lanes; } private void parseFeatures(FileReader fileReader) throws IOException, ParseException { @@ -317,9 +208,27 @@ private void parseFeatures(FileReader fileReader) throws IOException, ParseExcep this.features = (JSONArray) jsonObject.get("features"); } - private class GeoJSONException extends Exception { - GeoJSONException(JSONObject properties, String key) { - super("Missing key: \'" + key + "\' in GeoJSON properties: " + properties); + private void parseFeature(JSONObject feature) { + JSONObject properties = (JSONObject) feature.get("properties"); + JSONObject geometry = (JSONObject) feature.get("geometry"); + JSONArray coordinates = (JSONArray) geometry.get("coordinates"); + + String geometryType = (String) geometry.get("type"); + Boolean isOneWay = true; + if (properties.containsKey("oneway")) { + isOneWay = ((String) properties.get("oneway")).equalsIgnoreCase("yes"); + } + if (geometryType.equals("LineString")) { + JSONArray fromLatLon = (JSONArray) coordinates.get(0); + JSONArray toLatlon = (JSONArray) coordinates.get(coordinates.size() - 1); + int fromId = getOrCreateNode(fromLatLon, properties); + int toId = getOrCreateNode(toLatlon, properties); + addEdge(fromId, toId, properties, coordinates); + if (!isOneWay) { + addEdge(toId, fromId, properties, coordinates); + } + } else if (geometryType.equals("Point")) { + getOrCreateNode(coordinates, properties); } } } diff --git a/src/main/java/cz/cvut/fel/aic/graphimporter/osm/OsmImporter.java b/src/main/java/cz/cvut/fel/aic/graphimporter/osm/OsmImporter.java index 372a5e2..824ae4f 100644 --- a/src/main/java/cz/cvut/fel/aic/graphimporter/osm/OsmImporter.java +++ b/src/main/java/cz/cvut/fel/aic/graphimporter/osm/OsmImporter.java @@ -372,9 +372,11 @@ protected void createAndAddOrMergeEdge(long fromSourceId, long toSourceId, Set{ - - private final Map otherParams; - +public class InternalEdgeBuilder extends EdgeBuilder { + + private final Map otherParams; + private Set modeOfTransports = EnumSet.noneOf(TransportMode.class); - - public long wayID; // OsmWay ID - - public int uniqueWayID; - - public int oppositeWayUniqueId; // -1 if does not exists,otherwise uniqueWayId of the direction edge - - public float allowedMaxSpeedInMpS; - - public int lanesCount; - - public List coordinateList; - - - public InternalEdgeBuilder(int tmpFromId, int tmpToId, long osmWayId, int uniqueWayId, int oppositeWayUniqueId, int length, - Set modeOfTransports, float allowedMaxSpeedInMpS, Integer lanesCount, List coordinateList) { + + private int uniqueWayID; + + private int oppositeWayUniqueId; // -1 if does not exists,otherwise uniqueWayId of the direction edge + + private float allowedMaxSpeedInMpS; + + private int lanesCount; + + private List coordinateList; + + private List> lanesTurn; + + + public InternalEdgeBuilder(int tmpFromId, int tmpToId, int uniqueWayId, int oppositeWayUniqueId, int length, + Set modeOfTransports, float allowedMaxSpeedInMpS, Integer lanesCount, + List coordinateList, List> lanesTurn) { super(tmpFromId, tmpToId, length); - - this.wayID = osmWayId; + this.modeOfTransports = EnumSet.copyOf(modeOfTransports); this.uniqueWayID = uniqueWayId; this.oppositeWayUniqueId = oppositeWayUniqueId; @@ -51,10 +50,11 @@ public InternalEdgeBuilder(int tmpFromId, int tmpToId, long osmWayId, int unique this.allowedMaxSpeedInMpS = allowedMaxSpeedInMpS; this.lanesCount = lanesCount; this.coordinateList = coordinateList; - + this.lanesTurn = lanesTurn; + otherParams = new HashMap<>(); } - + public InternalEdgeBuilder addModeOfTransports(Set ModeOfTransports) { this.modeOfTransports.addAll(ModeOfTransports); return this; @@ -62,33 +62,33 @@ public InternalEdgeBuilder addModeOfTransports(Set ModeOfTranspor @Override public InternalEdge build(int fromId, int toId) { - otherParams.put("wayID", wayID); otherParams.put("uniqueWayID", uniqueWayID); otherParams.put("oppositeWayUniqueId", oppositeWayUniqueId); otherParams.put("modeOfTransports", modeOfTransports); otherParams.put("allowedMaxSpeedInMpS", allowedMaxSpeedInMpS); otherParams.put("lanesCount", lanesCount); otherParams.put("coordinateList", coordinateList); + otherParams.put("lanesTurn", lanesTurn); return new InternalEdge(fromId, toId, getLength(), otherParams); } @Override public boolean checkFeasibility(TransportMode mode) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public InternalEdgeBuilder copy(int tmpFromId, int tmpToId, int length) { - return new InternalEdgeBuilder(tmpFromId, tmpToId, wayID, uniqueWayID, oppositeWayUniqueId, - length, modeOfTransports, allowedMaxSpeedInMpS, lanesCount, coordinateList); + return new InternalEdgeBuilder(tmpFromId, tmpToId, uniqueWayID, oppositeWayUniqueId, + length, modeOfTransports, allowedMaxSpeedInMpS, lanesCount, coordinateList,lanesTurn); } - + public boolean equalAttributes(InternalEdgeBuilder that) { - return wayID == that.wayID - && lanesCount == that.lanesCount + return uniqueWayID == that.uniqueWayID + &&lanesCount == that.lanesCount && (modeOfTransports != null ? modeOfTransports.equals(that.modeOfTransports) && Float.compare(that.allowedMaxSpeedInMpS, allowedMaxSpeedInMpS) == 0 : that.modeOfTransports == null); } - + }