Skip to content
Snippets Groups Projects
Commit 66632692 authored by lazarog98's avatar lazarog98 Committed by theiled00
Browse files

Makes Json processing waaay more efficient (and also more faster). Use of Gson...

parent db1415b3
No related branches found
No related tags found
1 merge request!25Makes Json processing waaay more efficient (and also more faster). Use of Gson...
Showing
with 581 additions and 227 deletions
...@@ -34,6 +34,11 @@ ...@@ -34,6 +34,11 @@
<artifactId>json</artifactId> <artifactId>json</artifactId>
<version>20230227</version> <version>20230227</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency> <dependency>
<groupId>de.fuberlin.navigator</groupId> <groupId>de.fuberlin.navigator</groupId>
<artifactId>proto</artifactId> <artifactId>proto</artifactId>
......
package map.builder; package map.builder;
import java.io.IOException;
import map.builder.utilities.Config;
import org.json.JSONArray;
import de.fuberlin.navigator.protos.map_builder.RoadNetwork; import de.fuberlin.navigator.protos.map_builder.RoadNetwork;
import map.builder.osm.OSMFetcher; import map.builder.osm.OSMFetcher;
import map.builder.osm.OSMParser; import map.builder.osm.OSMParser;
import map.builder.osm.json.model.OSMJsonDto;
import map.builder.utilities.BoundingBox; import map.builder.utilities.BoundingBox;
import map.builder.utilities.Config;
import map.builder.utilities.FileHandler; import map.builder.utilities.FileHandler;
import java.io.IOException;
import java.util.List;
import static map.builder.utilities.Config.ROAD_NETWORK_OUTPUT_PATH; import static map.builder.utilities.Config.ROAD_NETWORK_OUTPUT_PATH;
public class App { public class App {
...@@ -29,17 +29,17 @@ public class App { ...@@ -29,17 +29,17 @@ public class App {
float maxLon = 14.330334220133722f; float maxLon = 14.330334220133722f;
*/ */
// BBox around central and south Brandenburg // BBox around Central + South Brandenburg (about 1.2GB in size)
float minLat = 51.968768f; float minLat = 52.788831211664586f;
float minLon = 12.144459f; float minLon = 11.333053381241731f;
float maxLat = 52.674160f; float maxLat = 50.92993593954551f;
float maxLon = 15.016778f; float maxLon = 14.714574575766516f;
BoundingBox bbox = new BoundingBox(minLat, minLon, maxLat, maxLon); BoundingBox bbox = new BoundingBox(minLat, minLon, maxLat, maxLon);
JSONArray restrictions = OSMFetcher.fetchTurnRestrictions(bbox); List<OSMJsonDto> restrictions = OSMFetcher.fetchTurnRestrictions(bbox);
JSONArray roads = OSMFetcher.fetchNodesAndWays(bbox); List<OSMJsonDto> roads = OSMFetcher.fetchNodesAndWays(bbox);
OSMFetcher.dumpJsonData(roads, "test_data.json");
System.out.println("Starting to parse."); System.out.println("Starting to parse.");
parser.parseTurnRestrictions(restrictions); parser.parseTurnRestrictions(restrictions);
......
...@@ -9,12 +9,22 @@ import java.io.InputStream; ...@@ -9,12 +9,22 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import org.json.JSONArray; import java.util.List;
import java.util.stream.Collectors;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonReader;
import map.builder.osm.json.model.OSMJsonDto;
import map.builder.osm.json.serialization.OSMJsonDtoDeserializer;
import org.json.JSONObject; import org.json.JSONObject;
import map.builder.utilities.BoundingBox; import map.builder.utilities.BoundingBox;
import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.NODES_AND_WAYS;
import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.TURN_RESTRICTIONS;
public class OSMFetcher { public class OSMFetcher {
private final static String OverpassURL = "https://overpass.kumi.systems/api/interpreter"; private final static String OverpassURL = "https://overpass.kumi.systems/api/interpreter";
private final static String nodeQuery = "[out:json];way[highway](%s);(._;>;);out;"; private final static String nodeQuery = "[out:json];way[highway](%s);(._;>;);out;";
...@@ -23,28 +33,51 @@ public class OSMFetcher { ...@@ -23,28 +33,51 @@ public class OSMFetcher {
private OSMFetcher() { private OSMFetcher() {
} }
public static JSONArray fetchTurnRestrictions(BoundingBox boundingBox) throws IOException { public static List<OSMJsonDto> fetchTurnRestrictions(BoundingBox boundingBox) throws IOException {
System.out.println("Start to fetch turn restrictions."); System.out.println("Start to fetch turn restrictions.");
JSONArray jsonArray = OSMFetcher.runQueryForBBox(OSMFetcher.relationQuery, boundingBox); List<OSMJsonDto> dtos = OSMFetcher.runQueryForBBox(OSMFetcher.relationQuery, boundingBox, TURN_RESTRICTIONS);
System.out.println("Turn restrictions fetched."); System.out.println("Turn restrictions fetched.");
return jsonArray; return dtos;
} }
public static JSONArray fetchNodesAndWays(BoundingBox boundingBox) throws IOException { public static List<OSMJsonDto> fetchNodesAndWays(BoundingBox boundingBox) throws IOException {
System.out.println("Start to fetch nodes and ways."); System.out.println("Start to fetch nodes and ways.");
JSONArray jsonArray = OSMFetcher.runQueryForBBox(OSMFetcher.nodeQuery, boundingBox); List<OSMJsonDto> dtos = OSMFetcher.runQueryForBBox(OSMFetcher.nodeQuery, boundingBox, NODES_AND_WAYS);
System.out.println("Nodes and ways fetched."); System.out.println("Nodes and ways fetched.");
return jsonArray; return dtos;
} }
private static JSONArray runQueryForBBox(String query, BoundingBox bbox) throws IOException { private static List<OSMJsonDto> runQueryForBBox(String query, BoundingBox bbox, OSMJsonDtoDeserializer.Mode mode) throws IOException {
InputStream response = requestData(query, bbox); InputStream response = requestData(query, bbox);
JSONObject parsedResponse = getJSONObjectFromStream(response); JsonReader jsonReader = new JsonReader(new InputStreamReader(response));
List<OSMJsonDto> dtos = new ArrayList<>();
Gson gson = new GsonBuilder()
.registerTypeAdapter(OSMJsonDto.class, new OSMJsonDtoDeserializer(mode))
.create();
jsonReader.beginObject();
String key;
while ((key = jsonReader.nextName()) != null) {
if (key.equals("elements")) {
jsonReader.beginArray();
while (jsonReader.hasNext()) {
OSMJsonDto dto = gson.fromJson(jsonReader, OSMJsonDto.class);
if (dto != null) {
dtos.add(dto);
}
}
break;
}
jsonReader.skipValue();
}
return parsedResponse.getJSONArray("elements"); return dtos;
} }
private static InputStream requestData(String query, BoundingBox bbox) throws IOException { private static InputStream requestData(String query, BoundingBox bbox) throws IOException {
...@@ -65,26 +98,17 @@ public class OSMFetcher { ...@@ -65,26 +98,17 @@ public class OSMFetcher {
return connection.getInputStream(); return connection.getInputStream();
} }
private static JSONObject getJSONObjectFromStream(InputStream stream) throws IOException { public static void dumpJsonData(List<OSMJsonDto> data, String path) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(stream));
StringBuilder response = new StringBuilder(); // or StringBuffer if Java version 5+
String line;
while ((line = rd.readLine()) != null) {
response.append(line);
response.append('\n');
}
rd.close();
return new JSONObject(response.toString());
}
public static void dumpJsonData(JSONArray data, String path) throws IOException {
File yourFile = new File(path); File yourFile = new File(path);
yourFile.createNewFile(); yourFile.createNewFile();
FileWriter file = new FileWriter(path); FileWriter file = new FileWriter(path);
file.write(data.toString()); file.write(
"[" +
data.stream()
.map(OSMJsonDto::toJson)
.collect(Collectors.joining(", "))
+ "]"
);
file.close(); file.close();
} }
} }
package map.builder.osm;
import org.json.JSONObject;
import java.util.List;
import java.util.Objects;
public class OSMJSONUtils {
private OSMJSONUtils() {}
public static boolean isNode(JSONObject element) {
return Objects.equals(OSMJSONUtils.getType(element), "node");
}
public static boolean isWay(JSONObject element) {
return Objects.equals(OSMJSONUtils.getType(element), "way");
}
public static boolean isRelation(JSONObject element) {
return Objects.equals(OSMJSONUtils.getType(element), "relation");
}
public static boolean isTRFrom(JSONObject turnRestriction) {
return Objects.equals(OSMJSONUtils.getTRType(turnRestriction), "from");
}
public static boolean isTRTo(JSONObject turnRestriction) {
return Objects.equals(OSMJSONUtils.getTRType(turnRestriction), "to");
}
public static boolean isTRVia(JSONObject turnRestriction) {
return Objects.equals(OSMJSONUtils.getTRType(turnRestriction), "via");
}
public static String getType(JSONObject element) {
return element.getString(OSMKey.type.name());
}
public static String getTRType(JSONObject turnRestriction) {
return turnRestriction.getString(OSMKey.role.name());
}
public static boolean hasTag(JSONObject element, String tag) {
if (!element.has("tags")) {
return false;
}
JSONObject tags = element.getJSONObject("tags");
return tags.has(tag);
}
public static String getTag(JSONObject element, String tag) {
if (!OSMJSONUtils.hasTag(element, tag)) {
return null;
}
JSONObject tags = element.getJSONObject("tags");
return tags.getString(tag);
}
public static boolean isTagValueOneOf(JSONObject element, String tag, List<String> values) {
String tagValue = OSMJSONUtils.getTag(element, tag);
return values.contains(tagValue);
}
public static boolean isTagValueEqualTo(JSONObject element, String tag, String value) {
String tagValue = OSMJSONUtils.getTag(element, tag);
return Objects.equals(tagValue, value);
}
}
package map.builder.osm;
import map.builder.osm.json.model.*;
import org.json.JSONObject;
import java.util.List;
import java.util.Objects;
public class OSMJsonUtils {
private OSMJsonUtils() {}
public static boolean isNode(OSMJsonDto dto) {
return Objects.equals(OSMJsonUtils.getType(dto), "node") && dto instanceof OSMJsonNodeDto;
}
public static boolean isWay(OSMJsonDto dto) {
return Objects.equals(OSMJsonUtils.getType(dto), "way") && dto instanceof OSMJsonWayDto;
}
public static boolean isRelation(OSMJsonDto dto) {
return Objects.equals(OSMJsonUtils.getType(dto), "relation") && dto instanceof OSMJsonTurnRestrictionDto;
}
public static boolean isTRFrom(OSMJsonMemberDto dto) {
return Objects.equals(OSMJsonUtils.getTRType(dto), "from");
}
public static boolean isTRTo(OSMJsonMemberDto dto) {
return Objects.equals(OSMJsonUtils.getTRType(dto), "to");
}
public static boolean isTRVia(OSMJsonMemberDto dto) {
return Objects.equals(OSMJsonUtils.getTRType(dto), "via");
}
public static String getType(OSMJsonDto dto) {
return dto.getType();
}
public static String getTRType(OSMJsonMemberDto dto) {
return dto.getRole();
}
public static boolean hasTag(OSMJsonWayDto dto, String tag) {
return getTag(dto, tag) != null;
}
public static String getTag(OSMJsonWayDto dto, String tag) {
return switch (tag) {
case "highway" -> dto.getHighway();
case "junction" -> dto.getJunction();
default -> null;
};
}
public static boolean isTagValueEqualTo(OSMJsonWayDto dto, String tag, String value) {
String tagValue = getTag(dto, tag);
return Objects.equals(tagValue, value);
}
}
package map.builder.osm;
public enum OSMKey {
type, tags, nodes, id, uid, lon, lat, element, role, members, ref
}
...@@ -2,11 +2,9 @@ package map.builder.osm; ...@@ -2,11 +2,9 @@ package map.builder.osm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.regex.Matcher; import java.util.List;
import java.util.regex.Pattern;
import org.json.JSONArray; import map.builder.osm.json.model.*;
import org.json.JSONObject;
import de.fuberlin.navigator.protos.map_builder.Coordinates; import de.fuberlin.navigator.protos.map_builder.Coordinates;
import de.fuberlin.navigator.protos.map_builder.Node; import de.fuberlin.navigator.protos.map_builder.Node;
...@@ -15,6 +13,7 @@ import de.fuberlin.navigator.protos.map_builder.RoadNetwork; ...@@ -15,6 +13,7 @@ import de.fuberlin.navigator.protos.map_builder.RoadNetwork;
import de.fuberlin.navigator.protos.map_builder.Segment; import de.fuberlin.navigator.protos.map_builder.Segment;
import map.builder.utilities.ComputationalUtils; import map.builder.utilities.ComputationalUtils;
public class OSMParser { public class OSMParser {
private final Coordinates.Builder coordinatesBuilder; private final Coordinates.Builder coordinatesBuilder;
private final HashMap<Long, Node> nodesDump; private final HashMap<Long, Node> nodesDump;
...@@ -27,33 +26,35 @@ public class OSMParser { ...@@ -27,33 +26,35 @@ public class OSMParser {
this.nodesDump = new HashMap<>(); this.nodesDump = new HashMap<>();
} }
public void parseRoads(JSONArray elements) { public void parseRoads(List<OSMJsonDto> elements) {
for (int i = 0; i < elements.length(); i++) { for (OSMJsonDto dto : elements) {
JSONObject element = elements.getJSONObject(i); if (OSMJsonUtils.isNode(dto)) {
this.createNode((OSMJsonNodeDto) dto);
if (OSMJSONUtils.isNode(element)) {
this.createNode(element);
} }
} }
for (int i = 0; i < elements.length(); i++) { for (OSMJsonDto dto : elements) {
JSONObject element = elements.getJSONObject(i); if (OSMJsonUtils.isWay(dto)) {
if (OSMJSONUtils.isWay(element) && SegmentUtils.isSegmentDrivable(element)) { OSMJsonWayDto wayDto = (OSMJsonWayDto) dto;
SegmentUtils.markEndNodes(element); if (SegmentUtils.isSegmentDrivable(wayDto)) {
SegmentUtils.markEndNodes(wayDto);
}
} }
} }
for (int i = 0; i < elements.length(); i++) { for (OSMJsonDto dto : elements) {
JSONObject element = elements.getJSONObject(i); if (OSMJsonUtils.isWay(dto)) {
if (OSMJSONUtils.isWay(element) && SegmentUtils.isSegmentDrivable(element)) { OSMJsonWayDto wayDto = (OSMJsonWayDto) dto;
this.splitSegment(element); if (SegmentUtils.isSegmentDrivable(wayDto)) {
this.splitSegment(wayDto);
}
} }
} }
} }
private void splitSegment(JSONObject element) { private void splitSegment(OSMJsonWayDto dto) {
JSONArray nodes = element.getJSONArray(OSMKey.nodes.name()); long[] nodes = dto.getNodes();
long osmId = element.getLong(OSMKey.id.name()); long osmId = dto.getOsmId();
ArrayList<ArrayList<Long>> geometry = SegmentUtils.splitGeometry(nodes); ArrayList<ArrayList<Long>> geometry = SegmentUtils.splitGeometry(nodes);
...@@ -62,12 +63,12 @@ public class OSMParser { ...@@ -62,12 +63,12 @@ public class OSMParser {
} }
for (int i = 0; i < geometry.size(); i++) { for (int i = 0; i < geometry.size(); i++) {
this.createSegment(element, geometry.get(i)); this.createSegment(dto, geometry.get(i));
} }
} }
private void createSegment(JSONObject element, ArrayList<Long> geometry) { private void createSegment(OSMJsonWayDto dto, ArrayList<Long> geometry) {
long osmId = element.getLong(OSMKey.id.name()); long osmId = dto.getOsmId();
ArrayList<Coordinates> line = null; ArrayList<Coordinates> line = null;
try { try {
...@@ -82,13 +83,8 @@ public class OSMParser { ...@@ -82,13 +83,8 @@ public class OSMParser {
long startNodeId = geometry.get(0); long startNodeId = geometry.get(0);
long endNodeId = geometry.get(geometry.size() - 1); long endNodeId = geometry.get(geometry.size() - 1);
boolean oneWay = this.isOneWay(element); boolean oneWay = SegmentUtils.isSegmentOneway(dto);
int maxSpeed = SegmentUtils.getMaxSpeed(element); int maxSpeed = SegmentUtils.getMaxSpeed(dto);
/*
System.out.printf("Max speed: %d \n", maxSpeed);
System.out.printf("Way id: %d, Start node id : %d, End node id: %d \n", osmId, startNodeId, endNodeId);
*/
int internalId = this.roadNetworkBuilder.getSegmentsCount(); int internalId = this.roadNetworkBuilder.getSegmentsCount();
...@@ -98,7 +94,7 @@ public class OSMParser { ...@@ -98,7 +94,7 @@ public class OSMParser {
.setOneWay(oneWay) .setOneWay(oneWay)
.setMaxSpeed(maxSpeed) .setMaxSpeed(maxSpeed)
.setId(internalId) .setId(internalId)
.setCategory(SegmentUtils.parseRoadType(element)) .setCategory(SegmentUtils.parseRoadType(dto))
.setStartNode(startNodeId) .setStartNode(startNodeId)
.setEndNode(endNodeId) .setEndNode(endNodeId)
.setLength(this.computeSegmentLength(line)) .setLength(this.computeSegmentLength(line))
...@@ -107,28 +103,21 @@ public class OSMParser { ...@@ -107,28 +103,21 @@ public class OSMParser {
this.roadNetworkBuilder.putSegments(internalId, segment); this.roadNetworkBuilder.putSegments(internalId, segment);
} }
private boolean isOneWay(JSONObject element) {
return OSMJSONUtils.isTagValueEqualTo(element, "oneway", "yes") ||
OSMJSONUtils.isTagValueEqualTo(element, "highway", "motorway") ||
OSMJSONUtils.isTagValueEqualTo(element, "junction", "roundabout");
}
private void moveNodeToProto(Node node) { private void moveNodeToProto(Node node) {
long osmId = node.getOsmId(); long osmId = node.getOsmId();
this.roadNetworkBuilder.putNodes(osmId, node); this.roadNetworkBuilder.putNodes(osmId, node);
} }
private void createNode(JSONObject element) { private void createNode(OSMJsonNodeDto dto) {
Coordinates position = this.createLocationFromElement(element); Coordinates position = this.createLocationFromElement(dto.getLon(), dto.getLat());
long osmId = element.getLong(OSMKey.id.name());
Node node = Node.newBuilder() Node node = Node.newBuilder()
.setId(this.roadNetworkBuilder.getNodesCount()) .setId(this.roadNetworkBuilder.getNodesCount())
.setOsmId(osmId) .setOsmId(dto.getOsmId())
.setPosition(position) .setPosition(position)
.build(); .build();
this.nodesDump.put(osmId, node); this.nodesDump.put(dto.getOsmId(), node);
} }
private double computeSegmentLength(ArrayList<Coordinates> line) { private double computeSegmentLength(ArrayList<Coordinates> line) {
...@@ -163,6 +152,7 @@ public class OSMParser { ...@@ -163,6 +152,7 @@ public class OSMParser {
} }
if (i == 0 || i == nodeIds.size() - 1) { if (i == 0 || i == nodeIds.size() - 1) {
// if it is the first or last node, we need to save it to the proto // if it is the first or last node, we need to save it to the proto
moveNodeToProto(currentNode); moveNodeToProto(currentNode);
} }
...@@ -189,18 +179,17 @@ public class OSMParser { ...@@ -189,18 +179,17 @@ public class OSMParser {
throw new NullPointerException("Node with id " + osmId + " not found!"); throw new NullPointerException("Node with id " + osmId + " not found!");
} }
private Coordinates createLocationFromElement(JSONObject element) { private Coordinates createLocationFromElement(float lon, float lat) {
return coordinatesBuilder return coordinatesBuilder
.setLon(element.getFloat(OSMKey.lon.name())) .setLon(lon)
.setLat(element.getFloat(OSMKey.lat.name())) .setLat(lat)
.build(); .build();
} }
public void parseTurnRestrictions(JSONArray elements) { public void parseTurnRestrictions(List<OSMJsonDto> elements) {
for (int i = 0; i < elements.length(); i++) { for (OSMJsonDto dto : elements) {
JSONObject element = elements.getJSONObject(i); if (OSMJsonUtils.isRelation(dto)) {
if (OSMJSONUtils.isRelation(element)) { OSMJsonMemberDto[] members = ((OSMJsonTurnRestrictionDto) dto).getMembers();
JSONArray members = element.getJSONArray(OSMKey.members.name());
if (!hasWayVia(members)) { if (!hasWayVia(members)) {
parseFromTo(members); parseFromTo(members);
} }
...@@ -208,17 +197,16 @@ public class OSMParser { ...@@ -208,17 +197,16 @@ public class OSMParser {
} }
} }
private void parseFromTo(JSONArray elements) { private void parseFromTo(OSMJsonMemberDto[] members) {
if (!hasWayVia(elements)) { if (!hasWayVia(members)) {
int from = 0; int from = 0;
int to = 0; int to = 0;
for (int i = 0; i < elements.length(); i++) { for (OSMJsonMemberDto member : members) {
JSONObject element = elements.getJSONObject(i); if (OSMJsonUtils.isTRFrom(member)) {
if (OSMJSONUtils.isTRFrom(element)) { from = (int) member.getOsmId();
from = element.getInt(OSMKey.ref.name());
} }
if (OSMJSONUtils.isTRTo(element)) { if (OSMJsonUtils.isTRTo(member)) {
to = element.getInt(OSMKey.ref.name()); to = (int) member.getOsmId();
} }
} }
Restriction restriction = Restriction.newBuilder().setFromId(from).setToId(to).build(); Restriction restriction = Restriction.newBuilder().setFromId(from).setToId(to).build();
...@@ -226,14 +214,13 @@ public class OSMParser { ...@@ -226,14 +214,13 @@ public class OSMParser {
} }
} }
private boolean hasWayVia(JSONArray members) { private boolean hasWayVia(OSMJsonMemberDto[] members) {
if (members.length() < 3) { if (members.length < 3) {
return false; return false;
} }
for (int i = 0; i < members.length(); i++) { for (OSMJsonMemberDto member : members) {
JSONObject element = members.getJSONObject(i); if (OSMJsonUtils.isTRVia(member)) {
if (OSMJSONUtils.isTRVia(element)) { if (OSMJsonUtils.isWay(member)) {
if (OSMJSONUtils.isWay(element)) {
return true; return true;
} }
return false; return false;
......
package map.builder.osm; package map.builder.osm;
import de.fuberlin.navigator.protos.map_builder.RoadCategory; import de.fuberlin.navigator.protos.map_builder.RoadCategory;
import org.json.JSONObject; import map.builder.osm.json.model.OSMJsonWayDto;
import org.json.JSONArray;
import java.util.*;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static de.fuberlin.navigator.protos.map_builder.RoadCategory.*;
public class SegmentUtils { public class SegmentUtils {
// this is a hash-map to allow us to check if a node is a start/end node in linear time // this is a hash-map to allow us to check if a node is a start/end node in linear time
...@@ -37,21 +33,33 @@ public class SegmentUtils { ...@@ -37,21 +33,33 @@ public class SegmentUtils {
private static final Map<RoadCategory, Integer> speedMap = Map.ofEntries( private static final Map<RoadCategory, Integer> speedMap = Map.ofEntries(
Map.entry(RoadCategory.ROAD_CATEGORY_HIGHWAY, 120), Map.entry(RoadCategory.ROAD_CATEGORY_HIGHWAY, 120),
Map.entry(RoadCategory.ROAD_CATEGORY_MAIN, 90), Map.entry(RoadCategory.ROAD_CATEGORY_MAIN, 90),
Map.entry(RoadCategory.ROAD_CATEGORY_LOCAL, 50), Map.entry(ROAD_CATEGORY_LOCAL, 50),
Map.entry(RoadCategory.ROAD_CATEGORY_RESIDENTIAL, 30), Map.entry(ROAD_CATEGORY_RESIDENTIAL, 30),
Map.entry(RoadCategory.ROAD_CATEGORY_INVALID, 0)); Map.entry(ROAD_CATEGORY_INVALID, 0)
private static final Pattern patternMaxSpeed = Pattern );
.compile("^([0-9][\\.0-9]+?)(?:[ ]?(?:km/h|kmh|kph|mph|knots))?$"); private static final Pattern patternMaxSpeed = Pattern.compile("^([0-9][\\.0-9]+?)(?:[ ]?(?:km/h|kmh|kph|mph|knots))?$");
public static boolean isSegmentDrivable(JSONObject element) { public static boolean isSegmentDrivable(OSMJsonWayDto dto) {
return OSMJSONUtils.isTagValueOneOf(element, "highway", drivableRoads); if (dto.getHighway() == null) {
return false;
} }
public static RoadCategory parseRoadType(JSONObject element) { return drivableRoads.contains(dto.getHighway());
String roadTypeTag = OSMJSONUtils.getTag(element, OSMTag.highway.name()); }
return switch (roadTypeTag) { public static boolean isSegmentOneway(OSMJsonWayDto dto) {
case "motorway", "highway" -> RoadCategory.ROAD_CATEGORY_HIGHWAY; return dto.isOneway()
|| OSMJsonUtils.isTagValueEqualTo(dto, "highway", "motorway")
|| OSMJsonUtils.isTagValueEqualTo(dto, "junction", "roundabout");
}
public static RoadCategory parseRoadType(OSMJsonWayDto dto) {
if (dto.getHighway() == null) {
return ROAD_CATEGORY_INVALID;
}
return switch (dto.getHighway()) {
case "motorway", "highway" -> ROAD_CATEGORY_HIGHWAY;
case "trunk", "primary", "secondary", "motorway_link", "trunk_link", "primary_link", "secondary_link" -> case "trunk", "primary", "secondary", "motorway_link", "trunk_link", "primary_link", "secondary_link" ->
RoadCategory.ROAD_CATEGORY_MAIN; RoadCategory.ROAD_CATEGORY_MAIN;
case "unclassified", "tertiary", "tertiary_link", "track", "road" -> case "unclassified", "tertiary", "tertiary_link", "track", "road" ->
...@@ -61,13 +69,11 @@ public class SegmentUtils { ...@@ -61,13 +69,11 @@ public class SegmentUtils {
}; };
} }
public static int getMaxSpeed(JSONObject element) { public static int getMaxSpeed(OSMJsonWayDto dto) {
String maxSpeedTag = OSMTag.maxspeed.name();
// if there's a max speed tag, use it // if there's a max speed tag, use it
if (OSMJSONUtils.hasTag(element, maxSpeedTag)) { if (dto.getMaxspeed() != null) {
String maxspeed = OSMJSONUtils.getTag(element, maxSpeedTag); Matcher matcherMaxSpeed = SegmentUtils.patternMaxSpeed.matcher(dto.getMaxspeed());
Matcher matcherMaxSpeed = SegmentUtils.patternMaxSpeed.matcher(maxspeed);
if (matcherMaxSpeed.find()) { if (matcherMaxSpeed.find()) {
return Integer.parseInt(matcherMaxSpeed.group(1)); return Integer.parseInt(matcherMaxSpeed.group(1));
...@@ -75,15 +81,15 @@ public class SegmentUtils { ...@@ -75,15 +81,15 @@ public class SegmentUtils {
} }
// if no tag is available, parse the max speed based on road category // if no tag is available, parse the max speed based on road category
RoadCategory roadCategory = SegmentUtils.parseRoadType(element); RoadCategory roadCategory = SegmentUtils.parseRoadType(dto);
return SegmentUtils.speedMap.get(roadCategory); return SegmentUtils.speedMap.get(roadCategory);
} }
public static void markEndNodes(JSONObject element) { public static void markEndNodes(OSMJsonWayDto element) {
JSONArray nodes = element.getJSONArray(OSMKey.nodes.name()); long[] nodes = element.getNodes();
long startNodeId = nodes.getLong(0); long startNodeId = nodes[0];
long endNodeId = nodes.getLong(nodes.length() - 1); long endNodeId = nodes[nodes.length - 1];
System.out.println("marking " + startNodeId + " and " + endNodeId); System.out.println("marking " + startNodeId + " and " + endNodeId);
...@@ -91,23 +97,17 @@ public class SegmentUtils { ...@@ -91,23 +97,17 @@ public class SegmentUtils {
SegmentUtils.endNodes.put(endNodeId, true); SegmentUtils.endNodes.put(endNodeId, true);
} }
public static boolean isNodeAnEndNode(JSONObject element) {
long osmId = element.getLong(OSMKey.id.name());
return isNodeAnEndNode(osmId);
}
public static boolean isNodeAnEndNode(long osmId) { public static boolean isNodeAnEndNode(long osmId) {
return SegmentUtils.endNodes.containsKey(osmId); return SegmentUtils.endNodes.containsKey(osmId);
} }
public static ArrayList<ArrayList<Long>> splitGeometry(JSONArray nodes) { public static ArrayList<ArrayList<Long>> splitGeometry(long[] nodes) {
ArrayList<ArrayList<Long>> geometry = new ArrayList<>(); ArrayList<ArrayList<Long>> geometry = new ArrayList<>();
int from = -1; int from = -1;
for (int i = 0; i<nodes.length(); i++) { for (int i = 0; i < nodes.length; i++) {
long nodeId = nodes.getLong(i); long nodeId = nodes[i];
if (isNodeAnEndNode(nodeId)) { if (isNodeAnEndNode(nodeId)) {
if (from == -1) { if (from == -1) {
...@@ -130,11 +130,11 @@ public class SegmentUtils { ...@@ -130,11 +130,11 @@ public class SegmentUtils {
return geometry; return geometry;
} }
private static ArrayList<Long> extractIdsFromTo(JSONArray nodes, int from, int to) { private static ArrayList<Long> extractIdsFromTo(long[] nodes, int from, int to) {
ArrayList<Long> extractedIds = new ArrayList<>(); ArrayList<Long> extractedIds = new ArrayList<>();
for (int i = from; i <= to; i++) { for (int i = from; i <= to; i++) {
long nodeId = nodes.getLong(i); long nodeId = nodes[i];
extractedIds.add(nodeId); extractedIds.add(nodeId);
} }
......
package map.builder.osm.json.model;
public abstract class OSMJsonDto {
protected String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract String toJson();
}
package map.builder.osm.json.model;
public class OSMJsonMemberDto extends OSMJsonDto {
private String type;
private String role;
private long osmId;
@Override
public String getType() {
return type;
}
@Override
public void setType(String type) {
this.type = type;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public long getOsmId() {
return osmId;
}
public void setOsmId(long osmId) {
this.osmId = osmId;
}
@Override
public String toJson() {
return "{ type: " + type + ", role: " + role + ", osmId:" + osmId + " }";
}
}
package map.builder.osm.json.model;
public class OSMJsonNodeDto extends OSMJsonDto {
private long osmId;
private float lon;
private float lat;
public OSMJsonNodeDto() {
this.type = "node";
}
public long getOsmId() {
return osmId;
}
public void setOsmId(long osmId) {
this.osmId = osmId;
}
public float getLon() {
return lon;
}
public void setLon(float lon) {
this.lon = lon;
}
public float getLat() {
return lat;
}
public void setLat(float lat) {
this.lat = lat;
}
@Override
public String toJson() {
return "{ type: node, osmId: " + osmId + ", lon: " + lon + ", lat: " + lat + " }";
}
}
package map.builder.osm.json.model;
import java.util.Arrays;
import java.util.stream.Collectors;
public class OSMJsonTurnRestrictionDto extends OSMJsonDto {
private OSMJsonMemberDto[] members;
public OSMJsonTurnRestrictionDto() {
this.type = "relation";
}
public OSMJsonMemberDto[] getMembers() {
return members;
}
public void setMembers(OSMJsonMemberDto[] members) {
this.members = members;
}
@Override
public String toJson() {
String members = Arrays.asList(getMembers())
.stream()
.map(OSMJsonMemberDto::toJson)
.collect(Collectors.joining(", "));
return "{ type: relation, members: " + members + " }";
}
}
package map.builder.osm.json.model;
public class OSMJsonWayDto extends OSMJsonDto {
private long[] nodes;
private long osmId;
private String highway;
private boolean oneway;
private String junction;
private String maxspeed;
public OSMJsonWayDto() {
this.type = "way";
}
public long[] getNodes() {
return nodes;
}
public void setNodes(long[] nodes) {
this.nodes = nodes;
}
public long getOsmId() {
return osmId;
}
public void setOsmId(long osmId) {
this.osmId = osmId;
}
public String getHighway() {
return highway;
}
public void setHighway(String highway) {
this.highway = highway;
}
public boolean isOneway() {
return oneway;
}
public void setOneway(boolean oneway) {
this.oneway = oneway;
}
public String getJunction() {
return junction;
}
public void setJunction(String junction) {
this.junction = junction;
}
public String getMaxspeed() {
return maxspeed;
}
public void setMaxspeed(String maxspeed) {
this.maxspeed = maxspeed;
}
@Override
public String toJson() {
String nodes = "";
for (long node : this.nodes) {
nodes = nodes + node + ",";
}
return "{ type: way, nodes: [" + nodes + "], osmId: " + osmId + ", highway: " + highway + ", oneway: " + oneway + ", junction: "
+ junction + ", maxspeed: " + maxspeed + "}";
}
}
package map.builder.osm.json.serialization;
import com.google.gson.*;
import map.builder.osm.json.model.OSMJsonDto;
import java.lang.reflect.Type;
public class OSMJsonDtoDeserializer implements JsonDeserializer<OSMJsonDto> {
public enum Mode {
TURN_RESTRICTIONS, NODES_AND_WAYS;
}
private Mode mode;
public OSMJsonDtoDeserializer(Mode mode) {
this.mode = mode;
}
@Override
public OSMJsonDto deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
JsonObject object = jsonElement.getAsJsonObject();
OSMJsonDto dto = switch (object.get("type").getAsString()) {
case "relation" -> new OSMJsonTurnRestrictionDtoDeserializer().deserialize(object, mode);
case "node" -> new OSMJsonNodeDtoDeserializer().deserialize(object, mode);
case "way" -> new OSMJsonWayDtoDeserializer().deserialize(object, mode);
default -> null;
};
return dto;
}
}
package map.builder.osm.json.serialization;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import map.builder.osm.json.model.OSMJsonNodeDto;
import java.util.Iterator;
import java.util.Map;
import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.NODES_AND_WAYS;
public class OSMJsonNodeDtoDeserializer {
public OSMJsonNodeDto deserialize(JsonObject obj, OSMJsonDtoDeserializer.Mode mode) throws JsonParseException {
if (!mode.equals(NODES_AND_WAYS)) {
return null;
}
OSMJsonNodeDto dto = new OSMJsonNodeDto();
dto.setOsmId(obj.get("id").getAsLong());
dto.setLat(obj.get("lat").getAsFloat());
dto.setLon(obj.get("lon").getAsFloat());
return dto;
}
}
package map.builder.osm.json.serialization;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import map.builder.osm.json.model.OSMJsonMemberDto;
import map.builder.osm.json.model.OSMJsonTurnRestrictionDto;
import java.util.Iterator;
import java.util.Map;
import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.TURN_RESTRICTIONS;
public class OSMJsonTurnRestrictionDtoDeserializer {
public OSMJsonTurnRestrictionDto deserialize(JsonObject obj, OSMJsonDtoDeserializer.Mode mode) throws JsonParseException {
if (!mode.equals(TURN_RESTRICTIONS)) {
return null;
}
OSMJsonTurnRestrictionDto dto = new OSMJsonTurnRestrictionDto();
setMembers(obj.getAsJsonArray("members"), dto);
return dto;
}
public void setMembers(JsonArray elements, OSMJsonTurnRestrictionDto dto) {
OSMJsonMemberDto[] members = new OSMJsonMemberDto[elements.size()];
for (int i = 0; i < elements.size(); i++) {
JsonObject obj = elements.get(i).getAsJsonObject();
OSMJsonMemberDto member = new OSMJsonMemberDto();
member.setType(obj.get("type").getAsString());
member.setRole(obj.get("role").getAsString());
member.setOsmId(obj.get("ref").getAsLong());
members[i] = member;
}
dto.setMembers(members);
}
}
package map.builder.osm.json.serialization;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import map.builder.osm.json.model.OSMJsonWayDto;
import java.util.Iterator;
import java.util.Map;
import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.NODES_AND_WAYS;
public class OSMJsonWayDtoDeserializer {
public OSMJsonWayDto deserialize(JsonObject obj, OSMJsonDtoDeserializer.Mode mode) throws JsonParseException {
if (!mode.equals(NODES_AND_WAYS)) {
return null;
}
OSMJsonWayDto dto = new OSMJsonWayDto();
dto.setOsmId(obj.get("id").getAsLong());
setNodes(obj.getAsJsonArray("nodes"), dto);
resolveTags(obj.getAsJsonObject("tags"), dto);
return dto;
}
private void setNodes(JsonArray arr, OSMJsonWayDto dto) {
long[] nodes = new long[arr.size()];
for (int i = 0; i < arr.size(); i++) {
nodes[i] = arr.get(i).getAsLong();
}
dto.setNodes(nodes);
}
private void resolveTags(JsonObject obj, OSMJsonWayDto dto) {
Iterator<Map.Entry<String, JsonElement>> iterator = obj.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, JsonElement> entry = iterator.next();
switch (entry.getKey()) {
case "highway" -> dto.setHighway(entry.getValue().getAsString());
case "oneway" -> dto.setOneway(entry.getValue().getAsString().equals("yes"));
case "junction" -> dto.setJunction(entry.getValue().getAsString());
case "maxspeed" -> dto.setMaxspeed(entry.getValue().getAsString());
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment