kopia lustrzana https://github.com/onthegomap/planetiler
Add profile hooks for preprocessing OSM nodes and ways (#56)
rodzic
ad9d547ffc
commit
6f2dbc4f4b
|
@ -27,6 +27,10 @@ import java.util.function.Consumer;
|
|||
public abstract class ForwardingProfile implements Profile {
|
||||
|
||||
private final List<Handler> handlers = new ArrayList<>();
|
||||
/** Handlers that pre-process OSM nodes during pass 1 through the data. */
|
||||
private final List<OsmNodePreprocessor> osmNodePreprocessors = new ArrayList<>();
|
||||
/** Handlers that pre-process OSM ways during pass 1 through the data. */
|
||||
private final List<OsmWayPreprocessor> osmWayPreprocessors = new ArrayList<>();
|
||||
/** Handlers that pre-process OSM relations during pass 1 through the data. */
|
||||
private final List<OsmRelationPreprocessor> osmRelationPreprocessors = new ArrayList<>();
|
||||
/** Handlers that get a callback when each source is finished reading. */
|
||||
|
@ -53,6 +57,12 @@ public abstract class ForwardingProfile implements Profile {
|
|||
*/
|
||||
public void registerHandler(Handler handler) {
|
||||
this.handlers.add(handler);
|
||||
if (handler instanceof OsmNodePreprocessor osmNodePreprocessor) {
|
||||
osmNodePreprocessors.add(osmNodePreprocessor);
|
||||
}
|
||||
if (handler instanceof OsmWayPreprocessor osmWayPreprocessor) {
|
||||
osmWayPreprocessors.add(osmWayPreprocessor);
|
||||
}
|
||||
if (handler instanceof OsmRelationPreprocessor osmRelationPreprocessor) {
|
||||
osmRelationPreprocessors.add(osmRelationPreprocessor);
|
||||
}
|
||||
|
@ -65,6 +75,20 @@ public abstract class ForwardingProfile implements Profile {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessOsmNode(OsmElement.Node node) {
|
||||
for (OsmNodePreprocessor osmNodePreprocessor : osmNodePreprocessors) {
|
||||
osmNodePreprocessor.preprocessOsmNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessOsmWay(OsmElement.Way way) {
|
||||
for (OsmWayPreprocessor osmWayPreprocessor : osmWayPreprocessors) {
|
||||
osmWayPreprocessor.preprocessOsmWay(way);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OsmRelationInfo> preprocessOsmRelation(OsmElement.Relation relation) {
|
||||
// delegate OSM relation pre-processing to each layer, if it implements FeaturePostProcessor
|
||||
|
@ -159,6 +183,30 @@ public abstract class ForwardingProfile implements Profile {
|
|||
Consumer<FeatureCollector.Feature> emit);
|
||||
}
|
||||
|
||||
/** Handlers should implement this interface to pre-process OSM nodes during pass 1 through the data. */
|
||||
public interface OsmNodePreprocessor extends Handler {
|
||||
|
||||
/**
|
||||
* Extracts information from an OSM node during pass 1 of the input OSM data that the profile may need during
|
||||
* pass2.
|
||||
*
|
||||
* @see Profile#preprocessOsmNode(OsmElement.Node)
|
||||
*/
|
||||
void preprocessOsmNode(OsmElement.Node node);
|
||||
}
|
||||
|
||||
|
||||
/** Handlers should implement this interface to pre-process OSM ways during pass 1 through the data. */
|
||||
public interface OsmWayPreprocessor extends Handler {
|
||||
|
||||
/**
|
||||
* Extracts information from an OSM way during pass 1 of the input OSM data that the profile may need during pass2.
|
||||
*
|
||||
* @see Profile#preprocessOsmWay(OsmElement.Way)
|
||||
*/
|
||||
void preprocessOsmWay(OsmElement.Way way);
|
||||
}
|
||||
|
||||
/** Handlers should implement this interface to pre-process OSM relations during pass 1 through the data. */
|
||||
public interface OsmRelationPreprocessor extends Handler {
|
||||
|
||||
|
|
|
@ -32,6 +32,28 @@ import java.util.function.Consumer;
|
|||
public interface Profile {
|
||||
// TODO might want to break this apart into sub-interfaces that ForwardingProfile (and MbtilesMetadata) can use too
|
||||
|
||||
/**
|
||||
* Allows profile to extract any information it needs from a {@link OsmElement.Node} during the first pass through OSM
|
||||
* elements.
|
||||
* <p>
|
||||
* The default implementation does nothing.
|
||||
*
|
||||
* @param node the OSM node
|
||||
*/
|
||||
default void preprocessOsmNode(OsmElement.Node node) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows profile to extract any information it needs from a {@link OsmElement.Way} during the first pass through OSM
|
||||
* elements.
|
||||
* <p>
|
||||
* The default implementation does nothing.
|
||||
*
|
||||
* @param way the OSM way
|
||||
*/
|
||||
default void preprocessOsmWay(OsmElement.Way way) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts information from <a href="https://wiki.openstreetmap.org/wiki/Relation">OSM relations</a> that will be
|
||||
* passed along to {@link #processFeature(SourceFeature, FeatureCollector)} for any OSM element in that relation.
|
||||
|
|
|
@ -160,10 +160,12 @@ public class OsmReader implements Closeable, MemoryEstimator.HasEstimate {
|
|||
}
|
||||
if (readerElement instanceof ReaderNode node) {
|
||||
PASS1_NODES.inc();
|
||||
profile.preprocessOsmNode(OsmElement.fromGraphopper(node));
|
||||
// TODO allow limiting node storage to only ones that profile cares about
|
||||
nodeLocationDb.put(node.getId(), GeoUtils.encodeFlatLocation(node.getLon(), node.getLat()));
|
||||
} else if (readerElement instanceof ReaderWay) {
|
||||
} else if (readerElement instanceof ReaderWay way) {
|
||||
PASS1_WAYS.inc();
|
||||
profile.preprocessOsmWay(OsmElement.fromGraphopper(way));
|
||||
} else if (readerElement instanceof ReaderRelation rel) {
|
||||
PASS1_RELATIONS.inc();
|
||||
// don't leak graphhopper classes out through public API
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.onthegomap.planetiler.reader.SimpleFeature;
|
|||
import com.onthegomap.planetiler.reader.SourceFeature;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -25,6 +26,38 @@ public class ForwardingProfileTests {
|
|||
}
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testPreprocessOsmNode() {
|
||||
var node1 = new OsmElement.Node(1, 2, 3);
|
||||
var node2 = new OsmElement.Node(2, 3, 4);
|
||||
List<OsmElement.Node> calledWith = new ArrayList<>();
|
||||
profile.registerHandler((ForwardingProfile.OsmNodePreprocessor) calledWith::add);
|
||||
profile.preprocessOsmNode(node1);
|
||||
assertEquals(List.of(node1), calledWith);
|
||||
|
||||
List<OsmElement.Node> calledWith2 = new ArrayList<>();
|
||||
profile.registerHandler((ForwardingProfile.OsmNodePreprocessor) calledWith2::add);
|
||||
profile.preprocessOsmNode(node2);
|
||||
assertEquals(List.of(node1, node2), calledWith);
|
||||
assertEquals(List.of(node2), calledWith2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreprocessOsmWay() {
|
||||
var way1 = new OsmElement.Way(1);
|
||||
var way2 = new OsmElement.Way(2);
|
||||
List<OsmElement.Way> calledWith = new ArrayList<>();
|
||||
profile.registerHandler((ForwardingProfile.OsmWayPreprocessor) calledWith::add);
|
||||
profile.preprocessOsmWay(way1);
|
||||
assertEquals(List.of(way1), calledWith);
|
||||
|
||||
List<OsmElement.Way> calledWith2 = new ArrayList<>();
|
||||
profile.registerHandler((ForwardingProfile.OsmWayPreprocessor) calledWith2::add);
|
||||
profile.preprocessOsmWay(way2);
|
||||
assertEquals(List.of(way1, way2), calledWith);
|
||||
assertEquals(List.of(way2), calledWith2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreprocessOsmRelation() {
|
||||
record RelA(@Override long id) implements OsmRelationInfo {}
|
||||
|
|
|
@ -35,8 +35,10 @@ import java.nio.file.Path;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.BiConsumer;
|
||||
|
@ -1031,6 +1033,55 @@ public class PlanetilerTests {
|
|||
)), sortListValues(results.tiles));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreprocessOsmNodesAndWays() throws Exception {
|
||||
Set<Long> nodes1 = new HashSet<>();
|
||||
Set<Long> nodes2 = new HashSet<>();
|
||||
var profile = new Profile.NullProfile() {
|
||||
@Override
|
||||
public void preprocessOsmNode(OsmElement.Node node) {
|
||||
if (node.hasTag("a", "b")) {
|
||||
nodes1.add(node.id());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessOsmWay(OsmElement.Way way) {
|
||||
if (nodes1.contains(way.nodes().get(0))) {
|
||||
nodes2.add(way.nodes().get(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processFeature(SourceFeature sourceFeature, FeatureCollector features) {
|
||||
if (sourceFeature.isPoint() && nodes2.contains(sourceFeature.id())) {
|
||||
features.point("start_nodes")
|
||||
.setMaxZoom(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
var results = run(
|
||||
Map.of("threads", "1"),
|
||||
(featureGroup, p, config) -> processOsmFeatures(featureGroup, p, config, List.of(
|
||||
with(new ReaderNode(1, 0, 0), node -> node.setTag("a", "b")),
|
||||
new ReaderNode(2, GeoUtils.getWorldLat(0.375), 0),
|
||||
with(new ReaderWay(3), way -> {
|
||||
way.getNodes().add(1, 2);
|
||||
}),
|
||||
with(new ReaderWay(4), way -> {
|
||||
way.getNodes().add(1, 2);
|
||||
})
|
||||
)),
|
||||
profile
|
||||
);
|
||||
|
||||
assertSubmap(sortListValues(Map.of(
|
||||
TileCoord.ofXYZ(0, 0, 0), List.of(
|
||||
feature(newPoint(128, 128), Map.of())
|
||||
)
|
||||
)), sortListValues(results.tiles));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostProcessNodeUseLabelGridRank() throws Exception {
|
||||
double y = 0.5 + Z14_WIDTH / 2;
|
||||
|
@ -1421,11 +1472,11 @@ public class PlanetilerTests {
|
|||
throws GeometryException;
|
||||
}
|
||||
|
||||
private static record PlanetilerResults(
|
||||
private record PlanetilerResults(
|
||||
Map<TileCoord, List<TestUtils.ComparableFeature>> tiles, Map<String, String> metadata
|
||||
) {}
|
||||
|
||||
private static record TestProfile(
|
||||
private record TestProfile(
|
||||
@Override String name,
|
||||
@Override String description,
|
||||
@Override String attribution,
|
||||
|
|
Ładowanie…
Reference in New Issue