Skip to content
Snippets Groups Projects
Commit b434b6af authored by kraleva's avatar kraleva
Browse files

Merge branch 'main' of...

parents b7b95b85 8fcf44c5
No related branches found
No related tags found
1 merge request!26Add LLC
Showing
with 626 additions and 218 deletions
FROM eclipse-temurin:17-jdk-alpine FROM eclipse-temurin:19-jdk-alpine
ADD target/*-jar-with-dependencies.jar app.jar ADD target/*-jar-with-dependencies.jar app.jar
COPY src/main/resources/config.properties /data/configuration/config.properties
# Add the cron job # Add the cron job
# Calculate the map each day at 00:00 # Calculate the map each day at 00:00
# For testing: set it to * * * * * to run it each minute # For testing: set it to * * * * * to run it each minute
RUN echo "0 0 * * * java -jar /app.jar" >> /var/spool/cron/crontabs/root RUN echo "0 0 * * * java -jar -Xmx10g /app.jar" >> /var/spool/cron/crontabs/root
# Start the cron deamon # Start the cron deamon
CMD crond -f CMD crond -f
\ No newline at end of file
...@@ -24,11 +24,6 @@ ...@@ -24,11 +24,6 @@
<version>4.11</version> <version>4.11</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
......
package map.builder; package map.builder;
import static map.builder.utilities.Config.ROAD_NETWORK_OUTPUT_PATH;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import de.fuberlin.navigator.protos.map_builder.RoadNetwork; import de.fuberlin.navigator.protos.map_builder.RoadNetwork;
import map.builder.osm.OSMConnectedComponentParser; import map.builder.osm.OSMConnectedComponentParser;
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.ConnectedComponentGraph; import map.builder.utilities.ConnectedComponentGraph;
import map.builder.utilities.FileHandler; import map.builder.utilities.FileHandler;
public class App { public class App {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
System.out.println("Map builder started!");
Config.load();
RoadNetwork.Builder roadNetworkBuilder = RoadNetwork.newBuilder(); RoadNetwork.Builder roadNetworkBuilder = RoadNetwork.newBuilder();
OSMParser parser = new OSMParser(); OSMParser parser = new OSMParser();
...@@ -42,12 +48,13 @@ public class App { ...@@ -42,12 +48,13 @@ public class App {
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.");
parser.parseTurnRestrictions(restrictions); parser.parseTurnRestrictions(restrictions);
parser.parseRoads(roads); parser.parseRoads(roads);
System.out.println("Parsed road network.");
// set it to 0 so that it can be collected by garbage collector // set it to 0 so that it can be collected by garbage collector
restrictions = null; restrictions = null;
...@@ -70,6 +77,6 @@ public class App { ...@@ -70,6 +77,6 @@ public class App {
System.out.println("Turn restrictions count: " + roadNetwork.getTurnRestrictionsCount()); System.out.println("Turn restrictions count: " + roadNetwork.getTurnRestrictionsCount());
System.out.println("Nodes count: " + roadNetwork.getNodesCount()); System.out.println("Nodes count: " + roadNetwork.getNodesCount());
System.out.println("Segments count: " + roadNetwork.getSegmentsCount()); System.out.println("Segments count: " + roadNetwork.getSegmentsCount());
FileHandler.saveToFile(roadNetwork, "./roadnetwork_sample.proto"); FileHandler.saveToFile(roadNetwork, ROAD_NETWORK_OUTPUT_PATH);
} }
} }
...@@ -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,20 +33,51 @@ public class OSMFetcher { ...@@ -23,20 +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 {
return OSMFetcher.runQueryForBBox(OSMFetcher.relationQuery, boundingBox); System.out.println("Start to fetch turn restrictions.");
List<OSMJsonDto> dtos = OSMFetcher.runQueryForBBox(OSMFetcher.relationQuery, boundingBox, TURN_RESTRICTIONS);
System.out.println("Turn restrictions fetched.");
return dtos;
} }
public static JSONArray fetchNodesAndWays(BoundingBox boundingBox) throws IOException { public static List<OSMJsonDto> fetchNodesAndWays(BoundingBox boundingBox) throws IOException {
return OSMFetcher.runQueryForBBox(OSMFetcher.nodeQuery, boundingBox); System.out.println("Start to fetch nodes and ways.");
List<OSMJsonDto> dtos = OSMFetcher.runQueryForBBox(OSMFetcher.nodeQuery, boundingBox, NODES_AND_WAYS);
System.out.println("Nodes and ways fetched.");
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 {
...@@ -57,26 +98,17 @@ public class OSMFetcher { ...@@ -57,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,14 +2,17 @@ package map.builder.osm; ...@@ -2,14 +2,17 @@ package map.builder.osm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
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;
import de.fuberlin.navigator.protos.map_builder.Restriction; import de.fuberlin.navigator.protos.map_builder.Restriction;
import de.fuberlin.navigator.protos.map_builder.Segment; import de.fuberlin.navigator.protos.map_builder.Segment;
import map.builder.osm.json.model.OSMJsonDto;
import map.builder.osm.json.model.OSMJsonMemberDto;
import map.builder.osm.json.model.OSMJsonNodeDto;
import map.builder.osm.json.model.OSMJsonTurnRestrictionDto;
import map.builder.osm.json.model.OSMJsonWayDto;
import map.builder.utilities.ComputationalUtils; import map.builder.utilities.ComputationalUtils;
public class OSMParser { public class OSMParser {
...@@ -27,34 +30,36 @@ public class OSMParser { ...@@ -27,34 +30,36 @@ 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);
...@@ -63,12 +68,12 @@ public class OSMParser { ...@@ -63,12 +68,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,8 +87,8 @@ public class OSMParser { ...@@ -82,8 +87,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("Max speed: %d \n", maxSpeed);
System.out.printf("Way id: %d, Start node id : %d, End node id: %d \n", osmId, System.out.printf("Way id: %d, Start node id : %d, End node id: %d \n", osmId,
...@@ -98,7 +103,7 @@ public class OSMParser { ...@@ -98,7 +103,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 +112,21 @@ public class OSMParser { ...@@ -107,28 +112,21 @@ public class OSMParser {
this.segments.put(internalId, segment); this.segments.put(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.nodes.put(osmId, node); this.nodes.put(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.nodes.size() + this.nodesDump.size()) .setId(this.nodes.size() + this.nodesDump.size())
.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) {
...@@ -165,6 +163,7 @@ public class OSMParser { ...@@ -165,6 +163,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);
} }
...@@ -190,18 +189,17 @@ public class OSMParser { ...@@ -190,18 +189,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);
} }
...@@ -209,17 +207,16 @@ public class OSMParser { ...@@ -209,17 +207,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();
...@@ -227,14 +224,13 @@ public class OSMParser { ...@@ -227,14 +224,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());
}
}
}
}
package map.builder.utilities;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class Config {
private Config() {
}
private static Properties props = new Properties();
public static String ROAD_NETWORK_OUTPUT_PATH = "roadnetwork.proto";
public static void load() {
//The config is used for running the application in a Docker container
String configFilePath = "/data/configuration/config.properties";
try (FileInputStream is = new FileInputStream(configFilePath)){
props.load(is);
ROAD_NETWORK_OUTPUT_PATH = props.getProperty("ROAD_NETWORK_OUTPUT_PATH", ROAD_NETWORK_OUTPUT_PATH);
System.out.println("Config loaded.");
} catch (FileNotFoundException e) {
// Either way the Docker image was build wrong or this is not
// run in a Docker environment
System.out.println("No config file found. Using default settings!");
} catch (IOException e) {
// Something else went wrong, but we will
// not let this escalate
e.printStackTrace();
}
}
}
# Standard config for Docker
ROAD_NETWORK_OUTPUT_PATH = /data/road_network/roadnetwork.proto
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment