kopia lustrzana https://github.com/onthegomap/planetiler
Permit post-process merging in custommap schemas (#626)
rodzic
a1c33dc5d5
commit
ed707e6979
|
@ -192,6 +192,8 @@ A layer contains a thematically-related set of features from one or more input s
|
||||||
|
|
||||||
- `id` - Unique name of this layer
|
- `id` - Unique name of this layer
|
||||||
- `features` - A list of features contained in this layer. See [Layer Features](#layer-feature)
|
- `features` - A list of features contained in this layer. See [Layer Features](#layer-feature)
|
||||||
|
- `tile_post_process` - Optional processing operations to merge features with the same attributes in a rendered tile.
|
||||||
|
See [Tile Post Process](#tile-post-process)
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -201,6 +203,11 @@ layers:
|
||||||
features:
|
features:
|
||||||
- { ... }
|
- { ... }
|
||||||
- { ... }
|
- { ... }
|
||||||
|
tile_post_process:
|
||||||
|
merge_line_strings:
|
||||||
|
min_length: 1
|
||||||
|
tolerance: 1
|
||||||
|
buffer: 5
|
||||||
```
|
```
|
||||||
|
|
||||||
## Layer Feature
|
## Layer Feature
|
||||||
|
@ -279,6 +286,34 @@ tag_value: voltage
|
||||||
type: integer
|
type: integer
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Tile Post Process
|
||||||
|
|
||||||
|
Specific tile post processing operations for merging features may be defined:
|
||||||
|
|
||||||
|
- `merge_line_strings` - Combines linestrings with the same set of attributes into a multilinestring where segments with
|
||||||
|
touching endpoints are merged.
|
||||||
|
- `merge_polygons` - Combines polygons with the same set of attributes into a multipolygon where overlapping/touching polygons
|
||||||
|
are combined into fewer polygons covering the same area.
|
||||||
|
|
||||||
|
The follow attributes for `merge_line_strings` may be set:
|
||||||
|
- `min_length` - Minimum tile pixel length of features to emit, or 0 to emit all merged linestrings.
|
||||||
|
- `tolerance` - After merging, simplify linestrings using this pixel tolerance, or -1 to skip simplification step.
|
||||||
|
- `buffer` - Number of pixels outside the visible tile area to include detail for, or -1 to skip clipping step.
|
||||||
|
|
||||||
|
The follow attribute for `merge_polygons` may be set:
|
||||||
|
- `min_area` - Minimum area in square tile pixels of polygons to emit.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
merge_line_strings:
|
||||||
|
min_length: 1
|
||||||
|
tolerance: 1
|
||||||
|
buffer: 5
|
||||||
|
merge_polygons:
|
||||||
|
min_area: 1
|
||||||
|
```
|
||||||
|
|
||||||
## Data Type
|
## Data Type
|
||||||
|
|
||||||
A string enum that defines how to map from an input. Allowed values:
|
A string enum that defines how to map from an input. Allowed values:
|
||||||
|
|
|
@ -109,6 +109,10 @@
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/$defs/feature"
|
"$ref": "#/$defs/feature"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"tile_post_process": {
|
||||||
|
"description": "Optional processing operations to merge features with the same attributes in a rendered tile",
|
||||||
|
"$ref": "#/$defs/tile_post_process"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,6 +403,39 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tile_post_process": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"merge_line_strings": {
|
||||||
|
"description": "Combines linestrings with the same set of attributes into a multilinestring where segments with touching endpoints are merged",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"min_length": {
|
||||||
|
"description": "Minimum tile pixel length of features to emit, or 0 to emit all merged linestrings",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"tolerance": {
|
||||||
|
"description": "After merging, simplify linestrings using this pixel tolerance, or -1 to skip simplification step",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"buffer": {
|
||||||
|
"description": "Number of pixels outside the visible tile area to include detail for, or -1 to skip clipping step",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"merge_polygons": {
|
||||||
|
"description": "Combines polygons with the same set of attributes into a multipolygon where overlapping/touching polygons are combined into fewer polygons covering the same area",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"min_area": {
|
||||||
|
"description": "Minimum area in square tile pixels of polygons to emit",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"zoom_level": {
|
"zoom_level": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
|
|
|
@ -4,11 +4,14 @@ import static com.onthegomap.planetiler.expression.MultiExpression.Entry;
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
|
|
||||||
import com.onthegomap.planetiler.FeatureCollector;
|
import com.onthegomap.planetiler.FeatureCollector;
|
||||||
|
import com.onthegomap.planetiler.FeatureMerge;
|
||||||
import com.onthegomap.planetiler.Profile;
|
import com.onthegomap.planetiler.Profile;
|
||||||
|
import com.onthegomap.planetiler.VectorTile;
|
||||||
import com.onthegomap.planetiler.custommap.configschema.FeatureLayer;
|
import com.onthegomap.planetiler.custommap.configschema.FeatureLayer;
|
||||||
import com.onthegomap.planetiler.custommap.configschema.SchemaConfig;
|
import com.onthegomap.planetiler.custommap.configschema.SchemaConfig;
|
||||||
import com.onthegomap.planetiler.expression.MultiExpression;
|
import com.onthegomap.planetiler.expression.MultiExpression;
|
||||||
import com.onthegomap.planetiler.expression.MultiExpression.Index;
|
import com.onthegomap.planetiler.expression.MultiExpression.Index;
|
||||||
|
import com.onthegomap.planetiler.geo.GeometryException;
|
||||||
import com.onthegomap.planetiler.reader.SourceFeature;
|
import com.onthegomap.planetiler.reader.SourceFeature;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -25,6 +28,8 @@ public class ConfiguredProfile implements Profile {
|
||||||
|
|
||||||
private final SchemaConfig schema;
|
private final SchemaConfig schema;
|
||||||
|
|
||||||
|
private final Collection<FeatureLayer> layers;
|
||||||
|
private final Map<String, FeatureLayer> layersById = new HashMap<>();
|
||||||
private final Map<String, Index<ConfiguredFeature>> featureLayerMatcher;
|
private final Map<String, Index<ConfiguredFeature>> featureLayerMatcher;
|
||||||
private final TagValueProducer tagValueProducer;
|
private final TagValueProducer tagValueProducer;
|
||||||
private final Contexts.Root rootContext;
|
private final Contexts.Root rootContext;
|
||||||
|
@ -33,7 +38,7 @@ public class ConfiguredProfile implements Profile {
|
||||||
this.schema = schema;
|
this.schema = schema;
|
||||||
this.rootContext = rootContext;
|
this.rootContext = rootContext;
|
||||||
|
|
||||||
Collection<FeatureLayer> layers = schema.layers();
|
layers = schema.layers();
|
||||||
if (layers == null || layers.isEmpty()) {
|
if (layers == null || layers.isEmpty()) {
|
||||||
throw new IllegalArgumentException("No layers defined");
|
throw new IllegalArgumentException("No layers defined");
|
||||||
}
|
}
|
||||||
|
@ -44,6 +49,7 @@ public class ConfiguredProfile implements Profile {
|
||||||
|
|
||||||
for (var layer : layers) {
|
for (var layer : layers) {
|
||||||
String layerId = layer.id();
|
String layerId = layer.id();
|
||||||
|
layersById.put(layerId, layer);
|
||||||
for (var feature : layer.features()) {
|
for (var feature : layer.features()) {
|
||||||
var configuredFeature = new ConfiguredFeature(layerId, tagValueProducer, feature, rootContext);
|
var configuredFeature = new ConfiguredFeature(layerId, tagValueProducer, feature, rootContext);
|
||||||
var entry = new Entry<>(configuredFeature, configuredFeature.matchExpression());
|
var entry = new Entry<>(configuredFeature, configuredFeature.matchExpression());
|
||||||
|
@ -84,6 +90,36 @@ public class ConfiguredProfile implements Profile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VectorTile.Feature> postProcessLayerFeatures(String layer, int zoom,
|
||||||
|
List<VectorTile.Feature> items) throws GeometryException {
|
||||||
|
FeatureLayer featureLayer = findFeatureLayer(layer);
|
||||||
|
|
||||||
|
if (featureLayer.postProcess() == null) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (featureLayer.postProcess().mergeLineStrings() != null) {
|
||||||
|
var merge = featureLayer.postProcess().mergeLineStrings();
|
||||||
|
|
||||||
|
items = FeatureMerge.mergeLineStrings(items,
|
||||||
|
merge.minLength(), // after merging, remove lines that are still less than {minLength}px long
|
||||||
|
merge.tolerance(), // simplify output linestrings using a {tolerance}px tolerance
|
||||||
|
merge.buffer() // remove any detail more than {buffer}px outside the tile boundary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (featureLayer.postProcess().mergePolygons() != null) {
|
||||||
|
var merge = featureLayer.postProcess().mergePolygons();
|
||||||
|
|
||||||
|
items = FeatureMerge.mergeOverlappingPolygons(items,
|
||||||
|
merge.minArea() // after merging, remove polygons that are still less than {minArea} in square tile pixels
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String description() {
|
public String description() {
|
||||||
return schema.schemaDescription();
|
return schema.schemaDescription();
|
||||||
|
@ -98,4 +134,8 @@ public class ConfiguredProfile implements Profile {
|
||||||
});
|
});
|
||||||
return sources;
|
return sources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FeatureLayer findFeatureLayer(String layerId) {
|
||||||
|
return layersById.get(layerId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package com.onthegomap.planetiler.custommap.configschema;
|
package com.onthegomap.planetiler.custommap.configschema;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public record FeatureLayer(
|
public record FeatureLayer(
|
||||||
String id,
|
String id,
|
||||||
Collection<FeatureItem> features
|
Collection<FeatureItem> features,
|
||||||
|
@JsonProperty("tile_post_process") PostProcess postProcess
|
||||||
) {}
|
) {}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.onthegomap.planetiler.custommap.configschema;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public record MergeLineStrings(
|
||||||
|
@JsonProperty("min_length") double minLength,
|
||||||
|
@JsonProperty("tolerance") double tolerance,
|
||||||
|
@JsonProperty("buffer") double buffer
|
||||||
|
) {}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.onthegomap.planetiler.custommap.configschema;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public record MergePolygons(
|
||||||
|
@JsonProperty("min_area") double minArea
|
||||||
|
) {}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.onthegomap.planetiler.custommap.configschema;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public record PostProcess(
|
||||||
|
@JsonProperty("merge_line_strings") MergeLineStrings mergeLineStrings,
|
||||||
|
@JsonProperty("merge_polygons") MergePolygons mergePolygons
|
||||||
|
) {}
|
|
@ -0,0 +1,43 @@
|
||||||
|
schema_name: Railways
|
||||||
|
schema_description: Railways (layers outputting merged & un-merged lines)
|
||||||
|
attribution: <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>
|
||||||
|
args:
|
||||||
|
area:
|
||||||
|
description: Geofabrik area to download
|
||||||
|
default: greater-london
|
||||||
|
osm_url:
|
||||||
|
description: OSM URL to download
|
||||||
|
default: '${ args.area == "planet" ? "aws:latest" : ("geofabrik:" + args.area) }'
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: '${ args.osm_url }'
|
||||||
|
layers:
|
||||||
|
- id: railways_merged
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: line
|
||||||
|
min_zoom: 4
|
||||||
|
min_size: 0
|
||||||
|
include_when:
|
||||||
|
__all__:
|
||||||
|
- railway: rail
|
||||||
|
- usage: main
|
||||||
|
exclude_when:
|
||||||
|
service: __any__
|
||||||
|
tile_post_process:
|
||||||
|
merge_line_strings:
|
||||||
|
min_length: 0
|
||||||
|
tolerance: -1
|
||||||
|
buffer: -1
|
||||||
|
- id: railways_unmerged
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: line
|
||||||
|
min_zoom: 4
|
||||||
|
include_when:
|
||||||
|
__all__:
|
||||||
|
- railway: rail
|
||||||
|
- usage: main
|
||||||
|
exclude_when:
|
||||||
|
service: __any__
|
|
@ -9,11 +9,17 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||||
import com.onthegomap.planetiler.FeatureCollector;
|
import com.onthegomap.planetiler.FeatureCollector;
|
||||||
import com.onthegomap.planetiler.FeatureCollector.Feature;
|
import com.onthegomap.planetiler.FeatureCollector.Feature;
|
||||||
import com.onthegomap.planetiler.Profile;
|
import com.onthegomap.planetiler.Profile;
|
||||||
|
import com.onthegomap.planetiler.VectorTile;
|
||||||
import com.onthegomap.planetiler.config.Arguments;
|
import com.onthegomap.planetiler.config.Arguments;
|
||||||
import com.onthegomap.planetiler.config.PlanetilerConfig;
|
import com.onthegomap.planetiler.config.PlanetilerConfig;
|
||||||
import com.onthegomap.planetiler.custommap.configschema.DataSourceType;
|
import com.onthegomap.planetiler.custommap.configschema.DataSourceType;
|
||||||
|
import com.onthegomap.planetiler.custommap.configschema.MergeLineStrings;
|
||||||
|
import com.onthegomap.planetiler.custommap.configschema.MergePolygons;
|
||||||
|
import com.onthegomap.planetiler.custommap.configschema.PostProcess;
|
||||||
import com.onthegomap.planetiler.custommap.configschema.SchemaConfig;
|
import com.onthegomap.planetiler.custommap.configschema.SchemaConfig;
|
||||||
import com.onthegomap.planetiler.custommap.util.TestConfigurableUtils;
|
import com.onthegomap.planetiler.custommap.util.TestConfigurableUtils;
|
||||||
|
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||||
|
import com.onthegomap.planetiler.geo.GeometryException;
|
||||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||||
import com.onthegomap.planetiler.reader.SourceFeature;
|
import com.onthegomap.planetiler.reader.SourceFeature;
|
||||||
import com.onthegomap.planetiler.stats.Stats;
|
import com.onthegomap.planetiler.stats.Stats;
|
||||||
|
@ -157,6 +163,89 @@ class ConfiguredFeatureTest {
|
||||||
testFeature(pathFunction, schemaFilename, sf, test, expectedMatchCount);
|
testFeature(pathFunction, schemaFilename, sf, test, expectedMatchCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFeaturePostProcessorNoop() throws GeometryException {
|
||||||
|
var config = """
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: geofabrik:rhode-island
|
||||||
|
local_path: data/rhode-island.osm.pbf
|
||||||
|
layers:
|
||||||
|
- id: testLayer
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: point
|
||||||
|
""";
|
||||||
|
var profile = loadConfig(config);
|
||||||
|
|
||||||
|
VectorTile.Feature feature = new VectorTile.Feature(
|
||||||
|
"testLayer",
|
||||||
|
1,
|
||||||
|
VectorTile.encodeGeometry(GeoUtils.point(0, 0)),
|
||||||
|
Map.of()
|
||||||
|
);
|
||||||
|
assertEquals(List.of(feature), profile.postProcessLayerFeatures("testLayer", 0, List.of(feature)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFeaturePostProcessorMergeLineStrings() throws GeometryException {
|
||||||
|
var config = """
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: geofabrik:rhode-island
|
||||||
|
local_path: data/rhode-island.osm.pbf
|
||||||
|
layers:
|
||||||
|
- id: testLayer
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: point
|
||||||
|
tile_post_process:
|
||||||
|
merge_line_strings:
|
||||||
|
min_length: 1
|
||||||
|
tolerance: 5
|
||||||
|
buffer: 10
|
||||||
|
""";
|
||||||
|
var profile = loadConfig(config);
|
||||||
|
|
||||||
|
VectorTile.Feature feature = new VectorTile.Feature(
|
||||||
|
"testLayer",
|
||||||
|
1,
|
||||||
|
VectorTile.encodeGeometry(GeoUtils.point(0, 0)),
|
||||||
|
Map.of()
|
||||||
|
);
|
||||||
|
assertEquals(List.of(feature), profile.postProcessLayerFeatures("testLayer", 0, List.of(feature)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFeaturePostProcessorMergePolygons() throws GeometryException {
|
||||||
|
var config = """
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: geofabrik:rhode-island
|
||||||
|
local_path: data/rhode-island.osm.pbf
|
||||||
|
layers:
|
||||||
|
- id: testLayer
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: point
|
||||||
|
tile_post_process:
|
||||||
|
merge_polygons:
|
||||||
|
min_area: 3
|
||||||
|
""";
|
||||||
|
var profile = loadConfig(config);
|
||||||
|
|
||||||
|
VectorTile.Feature feature = new VectorTile.Feature(
|
||||||
|
"testLayer",
|
||||||
|
1,
|
||||||
|
VectorTile.encodeGeometry(GeoUtils.point(0, 0)),
|
||||||
|
Map.of()
|
||||||
|
);
|
||||||
|
assertEquals(List.of(feature), profile.postProcessLayerFeatures("testLayer", 0, List.of(feature)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testStaticAttributeTest() {
|
void testStaticAttributeTest() {
|
||||||
testPolygon(TEST_RESOURCE, "static_attribute.yml", waterTags, f -> {
|
testPolygon(TEST_RESOURCE, "static_attribute.yml", waterTags, f -> {
|
||||||
|
@ -786,6 +875,7 @@ class ConfiguredFeatureTest {
|
||||||
void testInvalidSchemas() {
|
void testInvalidSchemas() {
|
||||||
testInvalidSchema("bad_geometry_type.yml", "Profile defined with invalid geometry type");
|
testInvalidSchema("bad_geometry_type.yml", "Profile defined with invalid geometry type");
|
||||||
testInvalidSchema("no_layers.yml", "Profile defined with no layers");
|
testInvalidSchema("no_layers.yml", "Profile defined with no layers");
|
||||||
|
testInvalidSchema("invalid_post_process.yml", "Profile defined with invalid post process element");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testInvalidSchema(String filename, String message) {
|
private void testInvalidSchema(String filename, String message) {
|
||||||
|
@ -1047,4 +1137,78 @@ class ConfiguredFeatureTest {
|
||||||
assertEquals(output, feature.getMinPixelSizeAtZoom(11));
|
assertEquals(output, feature.getMinPixelSizeAtZoom(11));
|
||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSchemaEmptyPostProcess() {
|
||||||
|
var config = """
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: geofabrik:rhode-island
|
||||||
|
local_path: data/rhode-island.osm.pbf
|
||||||
|
layers:
|
||||||
|
- id: testLayer
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: point
|
||||||
|
""";
|
||||||
|
this.planetilerConfig = PlanetilerConfig.from(Arguments.of(Map.of()));
|
||||||
|
assertNull(loadConfig(config).findFeatureLayer("testLayer").postProcess());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSchemaPostProcessWithMergeLineStrings() {
|
||||||
|
var config = """
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: geofabrik:rhode-island
|
||||||
|
local_path: data/rhode-island.osm.pbf
|
||||||
|
layers:
|
||||||
|
- id: testLayer
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: point
|
||||||
|
tile_post_process:
|
||||||
|
merge_line_strings:
|
||||||
|
min_length: 1
|
||||||
|
tolerance: 5
|
||||||
|
buffer: 10
|
||||||
|
""";
|
||||||
|
this.planetilerConfig = PlanetilerConfig.from(Arguments.of(Map.of()));
|
||||||
|
assertEquals(new PostProcess(
|
||||||
|
new MergeLineStrings(
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
10
|
||||||
|
),
|
||||||
|
null
|
||||||
|
), loadConfig(config).findFeatureLayer("testLayer").postProcess());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSchemaPostProcessWithMergePolygons() {
|
||||||
|
var config = """
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: geofabrik:rhode-island
|
||||||
|
local_path: data/rhode-island.osm.pbf
|
||||||
|
layers:
|
||||||
|
- id: testLayer
|
||||||
|
features:
|
||||||
|
- source: osm
|
||||||
|
geometry: point
|
||||||
|
tile_post_process:
|
||||||
|
merge_polygons:
|
||||||
|
min_area: 3
|
||||||
|
""";
|
||||||
|
this.planetilerConfig = PlanetilerConfig.from(Arguments.of(Map.of()));
|
||||||
|
assertEquals(new PostProcess(
|
||||||
|
null,
|
||||||
|
new MergePolygons(
|
||||||
|
3
|
||||||
|
)
|
||||||
|
), loadConfig(config).findFeatureLayer("testLayer").postProcess());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
schema_name: Test Case Schema
|
||||||
|
schema_description: Test case tile schema
|
||||||
|
attribution: Test attribution
|
||||||
|
sources:
|
||||||
|
osm:
|
||||||
|
type: osm
|
||||||
|
url: geofabrik:rhode-island
|
||||||
|
layers:
|
||||||
|
- id: testLayer
|
||||||
|
features:
|
||||||
|
- source:
|
||||||
|
- osm
|
||||||
|
geometry: line
|
||||||
|
include_when:
|
||||||
|
natural: water
|
||||||
|
attributes:
|
||||||
|
- key: water
|
||||||
|
- value: wet
|
||||||
|
tile_post_process:
|
||||||
|
merge_everything:
|
||||||
|
min_length: 1
|
Ładowanie…
Reference in New Issue