Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test the readers with osm-test data #816

Merged
merged 12 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.baremaps.openstreetmap.function;

import java.util.ArrayList;
import java.util.List;
import org.locationtech.jts.geom.*;

public class CleanDuplicatePoints {

public static Coordinate[] removeDuplicatePoints(Coordinate[] coord) {
List uniqueCoords = new ArrayList();
Coordinate lastPt = null;
for (int i = 0; i < coord.length; i++) {
if (lastPt == null || !lastPt.equals(coord[i])) {
lastPt = coord[i];
uniqueCoords.add(new Coordinate(lastPt));
}
}
return (Coordinate[]) uniqueCoords.toArray(new Coordinate[0]);
}

private GeometryFactory fact;

public CleanDuplicatePoints() {}

public Geometry clean(Geometry g) {
Fixed Show fixed Hide fixed
fact = g.getFactory();
if (g.isEmpty()) {
return g;
}
if (g instanceof Point) {
Fixed Show fixed Hide fixed
return g;
} else if (g instanceof MultiPoint) {
return g;
}
// LineString also handles LinearRings
else if (g instanceof LinearRing) {
return clean((LinearRing) g);
} else if (g instanceof LineString) {
return clean((LineString) g);
} else if (g instanceof Polygon) {
return clean((Polygon) g);
} else if (g instanceof MultiLineString) {
return clean((MultiLineString) g);
} else if (g instanceof MultiPolygon) {
return clean((MultiPolygon) g);
} else if (g instanceof GeometryCollection) {
return clean((GeometryCollection) g);
} else {
throw new UnsupportedOperationException(g.getClass().getName());
}
}

private LinearRing clean(LinearRing g) {
Coordinate[] coords = removeDuplicatePoints(g.getCoordinates());
return fact.createLinearRing(coords);
}

private LineString clean(LineString g) {
Fixed Show fixed Hide fixed
Coordinate[] coords = removeDuplicatePoints(g.getCoordinates());
return fact.createLineString(coords);
}

private Polygon clean(Polygon poly) {
Coordinate[] shellCoords = removeDuplicatePoints(poly.getExteriorRing().getCoordinates());
LinearRing shell = fact.createLinearRing(shellCoords);
List holes = new ArrayList();
for (int i = 0; i < poly.getNumInteriorRing(); i++) {
Coordinate[] holeCoords = removeDuplicatePoints(poly.getInteriorRingN(i).getCoordinates());
holes.add(fact.createLinearRing(holeCoords));
}
return fact.createPolygon(shell, GeometryFactory.toLinearRingArray(holes));
}

private MultiPolygon clean(MultiPolygon g) {
List polys = new ArrayList();
for (int i = 0; i < g.getNumGeometries(); i++) {
Polygon poly = (Polygon) g.getGeometryN(i);
polys.add(clean(poly));
}
return fact.createMultiPolygon(GeometryFactory.toPolygonArray(polys));
}

private MultiLineString clean(MultiLineString g) {
List lines = new ArrayList();
for (int i = 0; i < g.getNumGeometries(); i++) {
LineString line = (LineString) g.getGeometryN(i);
lines.add(clean(line));
}
return fact.createMultiLineString(GeometryFactory.toLineStringArray(lines));
}

private GeometryCollection clean(GeometryCollection g) {
Fixed Show fixed Hide fixed
List geoms = new ArrayList();
for (int i = 0; i < g.getNumGeometries(); i++) {
Geometry geom = g.getGeometryN(i);
geoms.add(clean(geom));
}
return fact.createGeometryCollection(GeometryFactory.toGeometryArray(geoms));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.apache.baremaps.openstreetmap.model.Node;
import org.apache.baremaps.openstreetmap.model.Relation;
import org.apache.baremaps.openstreetmap.model.Way;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.*;

/** A consumer that builds and sets the geometry of OpenStreetMap entities via side effects. */
public class EntityGeometryBuilder implements Consumer<Entity> {
Expand Down Expand Up @@ -59,4 +59,5 @@ public void accept(Entity entity) {
relationGeometryBuilder.accept(relation);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@

import java.util.function.Consumer;
import org.apache.baremaps.openstreetmap.model.Node;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.*;

/**
* A consumer that builds and sets a node geometry via side effects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,14 @@ public void accept(Relation relation) {
Map<String, Object> tags = relation.getTags();

// Filter out type that are not multipolygon or boundary geometries
// TODO: filter out at the stream level
if (!("multipolygon".equals(tags.get("type"))
|| "boundary".equals(tags.get("type")))) {
return;
}

// Filter coastline geometries
// TODO: document motivation for filtering out.
// TODO: filter out at the stream level
if ("coastline".equals(tags.get("natural"))) {
return;
}
Expand Down Expand Up @@ -117,7 +118,7 @@ private List<Polygon> mergeOuterAndInnerPolygons(Set<Polygon> outerPolygons,
Iterator<Polygon> it = innerPolygons.iterator();
while (it.hasNext()) {
Polygon innerPolygon = it.next();
if (prepared.containsProperly(innerPolygon)) {
if (prepared.contains(innerPolygon)) {
holes.add(innerPolygon.getExteriorRing());
it.remove();
}
Expand Down Expand Up @@ -177,8 +178,19 @@ private Set<Polygon> createPolygons(Relation relation, String role) {
private LineString createLine(Member member) {
try {
List<Long> refs = referenceMap.get(member.getRef());
List<Coordinate> coords = refs.stream().map(coordinateMap::get).toList();
Coordinate[] array = coords.toArray(new Coordinate[coords.size()]);

// Build the coordinate list and remove duplicates.
List<Coordinate> list = new ArrayList<>();
Coordinate previous = null;
for (Long id : refs) {
Coordinate coordinate = coordinateMap.get(id);
if (coordinate != null && !coordinate.equals(previous)) {
list.add(coordinate);
previous = coordinate;
}
}

Coordinate[] array = list.toArray(new Coordinate[0]);
return GEOMETRY_FACTORY_WGS84.createLineString(array);
} catch (Exception e) {
throw new StreamException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import static org.apache.baremaps.utils.GeometryUtils.GEOMETRY_FACTORY_WGS84;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.apache.baremaps.database.collection.DataMap;
Expand Down Expand Up @@ -51,9 +52,20 @@ public WayGeometryBuilder(DataMap<Long, Coordinate> coordinateMap) {
@Override
public void accept(Way way) {
try {
List<Coordinate> list = way.getNodes().stream().map(coordinateMap::get).toList();
// Build the coordinate list and remove duplicates.
List<Coordinate> list = new ArrayList<>();
Coordinate previous = null;
for (Long id : way.getNodes()) {
Coordinate coordinate = coordinateMap.get(id);
if (coordinate != null && !coordinate.equals(previous)) {
list.add(coordinate);
previous = coordinate;
}
}

Coordinate[] array = list.toArray(new Coordinate[list.size()]);
LineString line = GEOMETRY_FACTORY_WGS84.createLineString(array);

if (!line.isEmpty()) {
// Ways can be open or closed depending on the geometry or the tags:
// https://wiki.openstreetmap.org/wiki/Way
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,88 @@



import static org.apache.baremaps.stream.ConsumerUtils.consumeThenReturn;

import java.io.InputStream;
import java.util.List;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.baremaps.database.collection.DataMap;
import org.apache.baremaps.openstreetmap.OsmReader;
import org.apache.baremaps.openstreetmap.function.CoordinateMapBuilder;
import org.apache.baremaps.openstreetmap.function.EntityGeometryBuilder;
import org.apache.baremaps.openstreetmap.function.EntityProjectionTransformer;
import org.apache.baremaps.openstreetmap.function.ReferenceMapBuilder;
import org.apache.baremaps.openstreetmap.model.Entity;
import org.locationtech.jts.geom.Coordinate;

/** A utility class for parsing an OpenStreetMap XML file. */
public class XmlEntityReader implements OsmReader<Entity> {

private boolean geometry = false;

private int srid = 4326;

private DataMap<Long, Coordinate> coordinateMap;

private DataMap<Long, List<Long>> referenceMap;

public boolean geometries() {
return geometry;
}

public XmlEntityReader geometries(boolean geometries) {
this.geometry = geometries;
return this;
}

public int projection() {
return srid;
}

public XmlEntityReader projection(int srid) {
this.srid = srid;
return this;
}

public DataMap<Long, Coordinate> coordinateMap() {
return coordinateMap;
}

public XmlEntityReader coordinateMap(DataMap<Long, Coordinate> coordinateMap) {
this.coordinateMap = coordinateMap;
return this;
}

public DataMap<Long, List<Long>> referenceMap() {
return referenceMap;
}

public XmlEntityReader referenceMap(DataMap<Long, List<Long>> referenceMap) {
this.referenceMap = referenceMap;
return this;
}

/**
* Creates an ordered stream of OSM entities from a XML file.
*
* @param input
* @return
*/
public Stream<Entity> stream(InputStream input) {
return StreamSupport.stream(new XmlEntitySpliterator(input), false);
var entities = StreamSupport.stream(new XmlEntitySpliterator(input), false);
if (geometry) {
// Initialize and chain the entity handlers
var coordinateMapBuilder = new CoordinateMapBuilder(coordinateMap);
var referenceMapBuilder = new ReferenceMapBuilder(referenceMap);
var entityGeometryBuilder = new EntityGeometryBuilder(coordinateMap, referenceMap);
var entityProjectionTransformer = new EntityProjectionTransformer(4326, srid);
var entityHandler = coordinateMapBuilder
.andThen(referenceMapBuilder)
.andThen(entityGeometryBuilder)
.andThen(entityProjectionTransformer);
entities = entities.map(consumeThenReturn(entityHandler));
}
return entities;
}
}
Loading