/** * Requires vn to point to a relation element. From there it iterates over all matches of the ap. * Puts an empty list for each referenced way. */ private List<Tuple2<WayRole, Long>> extractWayRefs(VTDNav vn, Hashtable<Long, List<Long>> ways) throws NavException, XPathEvalException { vn.push(); List<Tuple2<WayRole, Long>> refs = new ArrayList<>(); for (int j = MEMBER_WAY_PATH.evalXPath(); j != -1; j = MEMBER_WAY_PATH.evalXPath()) { long ref = Long.parseLong(vn.toString(vn.getAttrVal("ref"))); String roleAsString = vn.toString(vn.getAttrVal("role")).toLowerCase(); WayRole role; switch (roleAsString) { case "inner": role = WayRole.INNER; break; case "outer": role = WayRole.OUTER; break; default: continue; } refs.add(Tuple.tuple(role, ref)); ways.put(ref, Collections.emptyList()); } MEMBER_WAY_PATH.resetXPath(); vn.pop(); return refs; }
private void extractReferencedWays( VTDNav vn, Hashtable<Long, List<Long>> ways, Hashtable<Long, Point2D> nodes) throws XPathEvalException, NavException { vn.push(); for (int i = WAY_PATH.evalXPath(); i != -1; i = WAY_PATH.evalXPath()) { long id = Long.parseLong(vn.toString(vn.getAttrVal("id"))); // By checking that we already referenced the id we can reduce memory pressure if (ways.containsKey(id)) { ways.put(id, extractNodeRefs(vn, nodes)); } } vn.pop(); }
/** * Requires vn to point to a way element. From there it iterates over all matches of the ap. Puts * a dummy point into nodes for every node it finds. */ private List<Long> extractNodeRefs(VTDNav vn, Hashtable<Long, Point2D> nodes) throws NavException, XPathEvalException { vn.push(); List<Long> refs = new ArrayList<>(); for (int j = NODE_REF_PATH.evalXPath(); j != -1; j = NODE_REF_PATH.evalXPath()) { long ref = Long.parseLong(vn.toString(j + 1)); refs.add(ref); nodes.put(ref, new Point2D(0, 0)); } NODE_REF_PATH.resetXPath(); vn.pop(); return refs; }
private List<List<Long>> extractWaysOfBuildings(VTDNav vn, Hashtable<Long, Point2D> nodes) throws XPathEvalException, NavException { vn.push(); List<List<Long>> ways = new ArrayList<>(); for (int i = BUILDING_WAY_PATH.evalXPath(); i != -1; i = BUILDING_WAY_PATH.evalXPath()) { // The lambda will put in a dummy value for each encountered node, // so that we know later which nodes we need to parse. ways.add(extractNodeRefs(vn, nodes)); } vn.pop(); BUILDING_WAY_PATH.resetXPath(); return ways; }
private List<List<Tuple2<WayRole, Long>>> extractWayRefsOfMultipolygons( VTDNav vn, Hashtable<Long, List<Long>> ways) throws NavException, XPathEvalException { vn.push(); List<List<Tuple2<WayRole, Long>>> multipolygons = new ArrayList<>(); for (int i = BUILDING_MULTIPOLYGON_PATH.evalXPath(); i != -1; i = BUILDING_MULTIPOLYGON_PATH.evalXPath()) { // For an explanation for the lambda see extractWaysOfBuildings multipolygons.add(extractWayRefs(vn, ways)); } vn.pop(); BUILDING_WAY_PATH.resetXPath(); return multipolygons; }
private void extractReferencedNodes(VTDNav vn, Hashtable<Long, Point2D> nodes) throws XPathEvalException, NavException { vn.push(); for (int i = NODE_PATH.evalXPath(); i != -1; i = NODE_PATH.evalXPath()) { long id = Long.parseLong(vn.toString(vn.getAttrVal("id"))); // By checking that we already referenced the id we can reduce memory pressure if (nodes.containsKey(id)) { nodes.put( id, new Point2D( Double.parseDouble(vn.toString(vn.getAttrVal("lon"))) * (1 << 10), Double.parseDouble(vn.toString(vn.getAttrVal("lat"))) * (1 << 10))); } } // Make sure we have all referenced nodes extracted // assert !nodes.containsValue(DUMMY_POINT); vn.pop(); }
public OSMGeometryParser() { try { NODE_PATH.selectXPath("/osm/node"); NODE_REF_PATH.selectXPath("nd/@ref"); BUILDING_WAY_PATH.selectXPath("/osm/way[./tag[@k='building']]"); BUILDING_MULTIPOLYGON_PATH.selectXPath( "/osm/relation[./tag[@k='type' and @v='multipolygon'] and ./tag/@k='building']"); MEMBER_WAY_PATH.selectXPath("member[@type='way']"); WAY_PATH.selectXPath("/osm/way"); } catch (XPathParseException e) { e.printStackTrace(); } }
public List<Triangle> parseFile(InputStream is) { try { VTDGen vg = new VTDGen(); vg.setDoc(IOUtils.toByteArray(is)); vg.parse(false); VTDNav vn = vg.getNav(); NODE_PATH.resetXPath(); NODE_PATH.bind(vn); // This is important state for the later method calls! NODE_REF_PATH.resetXPath(); NODE_REF_PATH.bind(vn); BUILDING_WAY_PATH.resetXPath(); BUILDING_WAY_PATH.bind(vn); BUILDING_MULTIPOLYGON_PATH.resetXPath(); BUILDING_MULTIPOLYGON_PATH.bind(vn); MEMBER_WAY_PATH.resetXPath(); MEMBER_WAY_PATH.bind(vn); WAY_PATH.resetXPath(); WAY_PATH.bind(vn); // A hash from node ids to actual node positions Hashtable<Long, Point2D> nodes = new Hashtable<>(); // A hash from way refs referenced from multipolygons to their actual list of node refs Hashtable<Long, List<Long>> multipolygonWays = new Hashtable<>(); // The following call initializes accessed node refs in nodes to a dummy value. List<List<Long>> buildingWays = extractWaysOfBuildings(vn, nodes); // The following call initializes accessed way refs from multipolygons to a dummy value. List<List<Tuple2<WayRole, Long>>> multipolygonWayRefs = extractWayRefsOfMultipolygons(vn, multipolygonWays); // This will extract all referenced multipolygon multipolygonWays, excluding the building // multipolygonWays // Also adds referenced nodes to nodes extractReferencedWays(vn, multipolygonWays, nodes); // This will extract all referenced nodes, but no more. extractReferencedNodes(vn, nodes); // Finally build the polygon list by following the node refs in wayRefs. // Triangulate each polygon and return the flattened list of triangles. // This way, poly2tri's types will not leak out of this class and we operate // on triangles anyway. return buildPolygons(nodes, buildingWays, multipolygonWays, multipolygonWayRefs) .flatMap( p -> { try { p.ComplexToSimplePolygon(); EarClipping ec = new EarClipping(p.SimplePolygon); return ec.Triangulation().stream(); } catch (RuntimeException ignored) { } return Stream.empty(); }) .toList(); } catch (XPathEvalException | NavException | IOException | ParseException e) { e.printStackTrace(); return new ArrayList<>(); } }