kopia lustrzana https://github.com/onthegomap/planetiler
Access OSM metadata in yaml profiles (#739)
rodzic
4efc2bbd41
commit
40bf33e887
|
@ -1,8 +1,10 @@
|
|||
package com.onthegomap.planetiler.reader;
|
||||
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmReader;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmSourceFeature;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -76,29 +78,87 @@ public class SimpleFeature extends SourceFeature {
|
|||
return new SimpleFeature(latLonGeometry, null, tags, null, null, idGenerator.incrementAndGet(), null);
|
||||
}
|
||||
|
||||
private static class SimpleOsmFeature extends SimpleFeature implements OsmSourceFeature {
|
||||
|
||||
private final String area;
|
||||
private final OsmElement.Info info;
|
||||
|
||||
private SimpleOsmFeature(Geometry latLonGeometry, Geometry worldGeometry, Map<String, Object> tags, String source,
|
||||
String sourceLayer, long id, List<OsmReader.RelationMember<OsmRelationInfo>> relations, OsmElement.Info info) {
|
||||
super(latLonGeometry, worldGeometry, tags, source, sourceLayer, id, relations);
|
||||
this.area = (String) tags.get("area");
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBePolygon() {
|
||||
return latLonGeometry() instanceof Polygonal || (latLonGeometry() instanceof LineString line &&
|
||||
OsmReader.canBePolygon(line.isClosed(), area, latLonGeometry().getNumPoints()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeLine() {
|
||||
return latLonGeometry() instanceof MultiLineString || (latLonGeometry() instanceof LineString line &&
|
||||
OsmReader.canBeLine(line.isClosed(), area, latLonGeometry().getNumPoints()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Geometry computePolygon() {
|
||||
var geom = worldGeometry();
|
||||
return geom instanceof LineString line ? GeoUtils.JTS_FACTORY.createPolygon(line.getCoordinates()) : geom;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OsmElement originalElement() {
|
||||
return new OsmElement() {
|
||||
@Override
|
||||
public long id() {
|
||||
return SimpleOsmFeature.this.id();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Info info() {
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cost() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> tags() {
|
||||
return tags();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o || (o instanceof SimpleOsmFeature other && super.equals(other) &&
|
||||
Objects.equals(area, other.area) && Objects.equals(info, other.info));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (area != null ? area.hashCode() : 0);
|
||||
result = 31 * result + (info != null ? info.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a new feature with OSM relation info. Useful for setting up inputs for OSM unit tests. */
|
||||
public static SimpleFeature createFakeOsmFeature(Geometry latLonGeometry, Map<String, Object> tags, String source,
|
||||
String sourceLayer, long id, List<OsmReader.RelationMember<OsmRelationInfo>> relations) {
|
||||
String area = (String) tags.get("area");
|
||||
return new SimpleFeature(latLonGeometry, null, tags, source, sourceLayer, id, relations) {
|
||||
@Override
|
||||
public boolean canBePolygon() {
|
||||
return latLonGeometry instanceof Polygonal || (latLonGeometry instanceof LineString line &&
|
||||
OsmReader.canBePolygon(line.isClosed(), area, latLonGeometry.getNumPoints()));
|
||||
}
|
||||
return createFakeOsmFeature(latLonGeometry, tags, source, sourceLayer, id, relations, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeLine() {
|
||||
return latLonGeometry instanceof MultiLineString || (latLonGeometry instanceof LineString line &&
|
||||
OsmReader.canBeLine(line.isClosed(), area, latLonGeometry.getNumPoints()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Geometry computePolygon() {
|
||||
var geom = worldGeometry();
|
||||
return geom instanceof LineString line ? GeoUtils.JTS_FACTORY.createPolygon(line.getCoordinates()) : geom;
|
||||
}
|
||||
};
|
||||
/** Returns a new feature with OSM relation info and metadata. Useful for setting up inputs for OSM unit tests. */
|
||||
public static SimpleFeature createFakeOsmFeature(Geometry latLonGeometry, Map<String, Object> tags, String source,
|
||||
String sourceLayer, long id, List<OsmReader.RelationMember<OsmRelationInfo>> relations, OsmElement.Info info) {
|
||||
return new SimpleOsmFeature(latLonGeometry, null, tags, source, sourceLayer, id, relations, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -485,6 +485,11 @@ nested, so each child context can also access the variables from its parent.
|
|||
>> - `feature.id` - numeric ID of the input feature
|
||||
>> - `feature.source` - string source ID this feature came from
|
||||
>> - `feature.source_layer` - optional layer within the source the feature came from
|
||||
>> - `feature.osm_changeset` - optional OSM changeset ID for this feature
|
||||
>> - `feature.osm_version` - optional OSM element version for this feature
|
||||
>> - `feature.osm_timestamp` - optional OSM last modified timestamp for this feature
|
||||
>> - `feature.osm_user_id` - optional ID of the OSM user that last modified this feature
|
||||
>> - `feature.osm_user_name` - optional name of the OSM user that last modified this feature
|
||||
>>
|
||||
>>> ##### post-match context
|
||||
>>>
|
||||
|
|
|
@ -13,6 +13,8 @@ import com.onthegomap.planetiler.expression.DataType;
|
|||
import com.onthegomap.planetiler.reader.SourceFeature;
|
||||
import com.onthegomap.planetiler.reader.WithGeometryType;
|
||||
import com.onthegomap.planetiler.reader.WithTags;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmSourceFeature;
|
||||
import com.onthegomap.planetiler.util.Try;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -340,6 +342,11 @@ public class Contexts {
|
|||
private static final String FEATURE_ID = "feature.id";
|
||||
private static final String FEATURE_SOURCE = "feature.source";
|
||||
private static final String FEATURE_SOURCE_LAYER = "feature.source_layer";
|
||||
private static final String FEATURE_OSM_CHANGESET = "feature.osm_changeset";
|
||||
private static final String FEATURE_OSM_VERSION = "feature.osm_version";
|
||||
private static final String FEATURE_OSM_TIMESTAMP = "feature.osm_timestamp";
|
||||
private static final String FEATURE_OSM_USER_ID = "feature.osm_user_id";
|
||||
private static final String FEATURE_OSM_USER_NAME = "feature.osm_user_name";
|
||||
|
||||
public static ScriptEnvironment<ProcessFeature> description(Root root) {
|
||||
return root.description()
|
||||
|
@ -348,7 +355,12 @@ public class Contexts {
|
|||
Decls.newVar(FEATURE_TAGS, Decls.newMapType(Decls.String, Decls.Any)),
|
||||
Decls.newVar(FEATURE_ID, Decls.Int),
|
||||
Decls.newVar(FEATURE_SOURCE, Decls.String),
|
||||
Decls.newVar(FEATURE_SOURCE_LAYER, Decls.String)
|
||||
Decls.newVar(FEATURE_SOURCE_LAYER, Decls.String),
|
||||
Decls.newVar(FEATURE_OSM_CHANGESET, Decls.Int),
|
||||
Decls.newVar(FEATURE_OSM_VERSION, Decls.Int),
|
||||
Decls.newVar(FEATURE_OSM_TIMESTAMP, Decls.Int),
|
||||
Decls.newVar(FEATURE_OSM_USER_ID, Decls.Int),
|
||||
Decls.newVar(FEATURE_OSM_USER_NAME, Decls.String)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -360,7 +372,17 @@ public class Contexts {
|
|||
case FEATURE_ID -> feature.id();
|
||||
case FEATURE_SOURCE -> feature.getSource();
|
||||
case FEATURE_SOURCE_LAYER -> wrapNullable(feature.getSourceLayer());
|
||||
default -> null;
|
||||
default -> {
|
||||
OsmElement.Info info = feature instanceof OsmSourceFeature osm ? osm.originalElement().info() : null;
|
||||
yield info == null ? null : switch (key) {
|
||||
case FEATURE_OSM_CHANGESET -> info.changeset();
|
||||
case FEATURE_OSM_VERSION -> info.version();
|
||||
case FEATURE_OSM_TIMESTAMP -> info.timestamp();
|
||||
case FEATURE_OSM_USER_ID -> info.userId();
|
||||
case FEATURE_OSM_USER_NAME -> wrapNullable(info.user());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.onthegomap.planetiler.geo.GeoUtils;
|
|||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import com.onthegomap.planetiler.reader.SourceFeature;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import com.onthegomap.planetiler.stats.Stats;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
@ -40,6 +41,7 @@ class ConfiguredFeatureTest {
|
|||
private static final Function<String, Path> TEST_RESOURCE = TestConfigurableUtils::pathToTestResource;
|
||||
private static final Function<String, Path> SAMPLE_RESOURCE = TestConfigurableUtils::pathToSample;
|
||||
private static final Function<String, Path> TEST_INVALID_RESOURCE = TestConfigurableUtils::pathToTestInvalidResource;
|
||||
private static final OsmElement.Info OSM_INFO = new OsmElement.Info(2, 3, 4, 5, "user");
|
||||
|
||||
private static final Map<String, Object> waterTags = Map.of(
|
||||
"natural", "water",
|
||||
|
@ -130,14 +132,15 @@ class ConfiguredFeatureTest {
|
|||
private void testPolygon(String config, Map<String, Object> tags,
|
||||
Consumer<Feature> test, int expectedMatchCount) {
|
||||
var sf =
|
||||
SimpleFeature.createFakeOsmFeature(newPolygon(0, 0, 1, 0, 1, 1, 0, 0), tags, "osm", null, 1, emptyList());
|
||||
SimpleFeature.createFakeOsmFeature(newPolygon(0, 0, 1, 0, 1, 1, 0, 0), tags, "osm", null, 1, emptyList(),
|
||||
OSM_INFO);
|
||||
testFeature(config, sf, test, expectedMatchCount);
|
||||
}
|
||||
|
||||
private void testPoint(String config, Map<String, Object> tags,
|
||||
Consumer<Feature> test, int expectedMatchCount) {
|
||||
var sf =
|
||||
SimpleFeature.createFakeOsmFeature(newPoint(0, 0), tags, "osm", null, 1, emptyList());
|
||||
SimpleFeature.createFakeOsmFeature(newPoint(0, 0), tags, "osm", null, 1, emptyList(), OSM_INFO);
|
||||
testFeature(config, sf, test, expectedMatchCount);
|
||||
}
|
||||
|
||||
|
@ -145,21 +148,22 @@ class ConfiguredFeatureTest {
|
|||
private void testLinestring(String config,
|
||||
Map<String, Object> tags, Consumer<Feature> test, int expectedMatchCount) {
|
||||
var sf =
|
||||
SimpleFeature.createFakeOsmFeature(newLineString(0, 0, 1, 0, 1, 1), tags, "osm", null, 1, emptyList());
|
||||
SimpleFeature.createFakeOsmFeature(newLineString(0, 0, 1, 0, 1, 1), tags, "osm", null, 1, emptyList(), OSM_INFO);
|
||||
testFeature(config, sf, test, expectedMatchCount);
|
||||
}
|
||||
|
||||
private void testPolygon(Function<String, Path> pathFunction, String schemaFilename, Map<String, Object> tags,
|
||||
Consumer<Feature> test, int expectedMatchCount) {
|
||||
var sf =
|
||||
SimpleFeature.createFakeOsmFeature(newPolygon(0, 0, 1, 0, 1, 1, 0, 0), tags, "osm", null, 1, emptyList());
|
||||
SimpleFeature.createFakeOsmFeature(newPolygon(0, 0, 1, 0, 1, 1, 0, 0), tags, "osm", null, 1, emptyList(),
|
||||
OSM_INFO);
|
||||
testFeature(pathFunction, schemaFilename, sf, test, expectedMatchCount);
|
||||
}
|
||||
|
||||
private void testLinestring(Function<String, Path> pathFunction, String schemaFilename,
|
||||
Map<String, Object> tags, Consumer<Feature> test, int expectedMatchCount) {
|
||||
var sf =
|
||||
SimpleFeature.createFakeOsmFeature(newLineString(0, 0, 1, 0, 1, 1), tags, "osm", null, 1, emptyList());
|
||||
SimpleFeature.createFakeOsmFeature(newLineString(0, 0, 1, 0, 1, 1), tags, "osm", null, 1, emptyList(), OSM_INFO);
|
||||
testFeature(pathFunction, schemaFilename, sf, test, expectedMatchCount);
|
||||
}
|
||||
|
||||
|
@ -547,6 +551,11 @@ class ConfiguredFeatureTest {
|
|||
"\\\\${feature.id}|\\${feature.id}",
|
||||
"${feature.source}|osm",
|
||||
"${feature.source_layer}|null",
|
||||
"${feature.osm_changeset}|2",
|
||||
"${feature.osm_timestamp}|3",
|
||||
"${feature.osm_user_id}|4",
|
||||
"${feature.osm_version}|5",
|
||||
"${feature.osm_user_name}|user",
|
||||
"${coalesce(feature.source_layer, 'missing')}|missing",
|
||||
"{match: {test: {natural: water}}}|test",
|
||||
"{match: {test: {natural: not_water}}}|null",
|
||||
|
|
Ładowanie…
Reference in New Issue