diff --git a/mapbuilder/src/main/java/map/builder/App.java b/mapbuilder/src/main/java/map/builder/App.java index 661048120670a5cc1d97ebdd16c1a1556fc7e93e..2a4b0326b68dd053004386e12061ce1745f9a28f 100644 --- a/mapbuilder/src/main/java/map/builder/App.java +++ b/mapbuilder/src/main/java/map/builder/App.java @@ -23,11 +23,19 @@ public class App { float maxLon = 14.330334220133722f; */ + // smaller BBox inside Cottbus, better for the debug tool + float minLat = 51.757799795929955f; + float minLon = 14.32136535644531f; + float maxLat = 51.770389396279654f; + float maxLon = 14.349260330200195f; + // BBox around Cottbus + /* float minLat = 51.714692361306376f; - float minLon = 14.261627197265625f; - float maxLat = 51.79120499625462f; - float maxLon = 14.391403198242188f; + float minLon = 14.26197052001953f; + float maxLat = 51.79290380494767f; + float maxLon = 14.415779113769531f; + */ BoundingBox bbox = new BoundingBox(minLat, minLon, maxLat, maxLon); @@ -42,6 +50,6 @@ public class App { System.out.println("Turn restrictions count: " + roadNetwork.getTurnRestrictionsCount()); System.out.println("Nodes count: " + roadNetwork.getNodesCount()); System.out.println("Segments count: " + roadNetwork.getSegmentsCount()); - FileHandler.saveToFile(roadNetwork, "./../routing-service/debug-tool/proto/sample/roadnetwork_sample.proto"); + FileHandler.saveToFile(roadNetwork, "./roadnetwork_sample.proto"); } } diff --git a/mapbuilder/src/main/java/map/builder/osm/OSMParser.java b/mapbuilder/src/main/java/map/builder/osm/OSMParser.java index f5e31768b502504f52c43ebf90d36026664860c2..d26b4d55f55f33c14c9c3aa3aae8f68314ac0e66 100644 --- a/mapbuilder/src/main/java/map/builder/osm/OSMParser.java +++ b/mapbuilder/src/main/java/map/builder/osm/OSMParser.java @@ -38,25 +38,45 @@ public class OSMParser { for (int i = 0; i < elements.length(); i++) { JSONObject element = elements.getJSONObject(i); - if (OSMJSONUtils.isWay(element)) { - if (SegmentUtils.isSegmentDrivable(element)) { - this.createSegment(element); - } + if (OSMJSONUtils.isWay(element) && SegmentUtils.isSegmentDrivable(element)) { + SegmentUtils.markEndNodes(element); + } + } + + for (int i = 0; i < elements.length(); i++) { + JSONObject element = elements.getJSONObject(i); + if (OSMJSONUtils.isWay(element) && SegmentUtils.isSegmentDrivable(element)) { + this.splitSegment(element); } } } - private void createSegment(JSONObject element) { + private void splitSegment(JSONObject element) { + JSONArray nodes = element.getJSONArray(OSMKey.nodes.name()); + long osmId = element.getLong(OSMKey.id.name()); + + ArrayList<ArrayList<Long>> geometry = SegmentUtils.splitGeometry(nodes); + + if (geometry.size() > 1) { + System.out.println("Split segment with ID " + osmId + " in " + geometry.size()); + } + + for (int i = 0; i<geometry.size(); i++) { + this.createSegment(element, geometry.get(i)); + } + } + + private void createSegment(JSONObject element, ArrayList<Long> geometry) { JSONArray nodes = element.getJSONArray(OSMKey.nodes.name()); long osmId = element.getLong(OSMKey.id.name()); ArrayList<Coordinates> line = null; try { - line = this.findNodePositions(nodes); + line = this.findNodePositions(geometry); } - catch (NullPointerException e) { - System.out.println("Dropping segment with ID " + osmId); - System.out.println(e.getMessage()); + catch (NullPointerException e) { + System.out.println("Dropping segment with ID " + osmId); + System.out.println(e.getMessage()); return; } @@ -69,19 +89,21 @@ public class OSMParser { 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); + long internalId = this.roadNetworkBuilder.getSegmentsCount(); + Segment segment = Segment.newBuilder() .setOsmId(osmId) - .addAllGeometry(line) + .addAllGeometry(this.findNodePositions(geometry)) .setOneWay(oneWay) .setMaxSpeed(maxSpeed) - .setId(this.roadNetworkBuilder.getSegmentsCount()) + .setId(internalId) .setCategory(SegmentUtils.parseRoadType(element)) .setStartNode(startNodeId) .setEndNode(endNodeId) .setLength(this.computeSegmentLength(line)) .build(); - this.roadNetworkBuilder.putSegments(osmId, segment); + this.roadNetworkBuilder.putSegments(internalId, segment); } private boolean isOneWay(JSONObject element) { @@ -121,18 +143,25 @@ public class OSMParser { return length; } - private ArrayList<Coordinates> findNodePositions(JSONArray nodeIds) throws NullPointerException { + /** + * Returns an array list of array lists of geometries. If the outer list has only one entry, it means the segment + * doesn't need to be split, otherwise it needs to. + * @param nodeIds + * @return + * @throws NullPointerException + */ + private ArrayList<Coordinates> findNodePositions(ArrayList<Long> nodeIds) throws NullPointerException { ArrayList<Coordinates> geometry = new ArrayList<>(); - for (int i = 0; i < nodeIds.length(); i++) { - long currentNodeId = nodeIds.getLong(i); + for (int i = 0; i < nodeIds.size(); i++) { + long currentNodeId = nodeIds.get(i); Node currentNode = this.findParsedNodeById(currentNodeId); if (currentNode == null) { return geometry; } - if (i == 0 || i == nodeIds.length() - 1) { + if (i == 0 || i == nodeIds.size() - 1) { // if it is the first or last node, we need to save it to the proto moveNodeToProto(currentNode); } diff --git a/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java b/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java index d5a79b377d0d7bcd9f390f19537d817b1dbc6364..49bea8c21b30e0c58861faa643718654e8974bdf 100644 --- a/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java +++ b/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java @@ -1,19 +1,22 @@ package map.builder.osm; +import de.fuberlin.navigator.protos.map_builder.RoadCategory; +import org.json.JSONObject; +import org.json.JSONArray; + +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.Pattern; -import org.json.JSONObject; - -import de.fuberlin.navigator.protos.map_builder.RoadCategory; public class SegmentUtils { - private SegmentUtils() { - } - + // this is a hash-map to allow us to check if a node is a start/end node in linear time + private SegmentUtils() {} + private static final HashMap<Long, Boolean> endNodes = new HashMap<>(); private static final List<String> drivableRoads = Arrays.asList( "motorway", "trunk", @@ -75,4 +78,64 @@ public class SegmentUtils { RoadCategory roadCategory = SegmentUtils.parseRoadType(element); return SegmentUtils.speedMap.get(roadCategory); } + + public static void markEndNodes(JSONObject element) { + JSONArray nodes = element.getJSONArray(OSMKey.nodes.name()); + + long startNodeId = nodes.getLong(0); + long endNodeId = nodes.getLong(nodes.length() - 1); + + System.out.println("marking " + startNodeId + " and " + endNodeId); + + SegmentUtils.endNodes.put(startNodeId, 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) { + return SegmentUtils.endNodes.containsKey(osmId); + } + + public static ArrayList<ArrayList<Long>> splitGeometry(JSONArray nodes) { + ArrayList<ArrayList<Long>> geometry = new ArrayList<>(); + + int from = -1; + + for (int i = 0; i<nodes.length(); i++) { + long nodeId = nodes.getLong(i); + + if (isNodeAnEndNode(nodeId)) { + if (from == -1) { + from = i; + } + else { + // extract node ids + ArrayList<Long> geometryNodeIds = extractIdsFromTo(nodes, from, i); + geometry.add(geometryNodeIds); + + System.out.println("Splitting at position " + from); + + from = i; + } + } + } + + return geometry; + } + + private static ArrayList<Long> extractIdsFromTo(JSONArray nodes, int from, int to) { + ArrayList<Long> extractedIds = new ArrayList<>(); + + for (int i = from; i<=to; i++) { + long nodeId = nodes.getLong(i); + extractedIds.add(nodeId); + } + + return extractedIds; + } }