Skip to content

Commit 442dcf3

Browse files
authored
Merge 7399aad into b07089b
2 parents b07089b + 7399aad commit 442dcf3

20 files changed

+1193
-285
lines changed

planetiler-core/src/main/java/com/onthegomap/planetiler/FeatureCollector.java

+42
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.onthegomap.planetiler.config.PlanetilerConfig;
66
import com.onthegomap.planetiler.geo.GeoUtils;
77
import com.onthegomap.planetiler.geo.GeometryException;
8+
import com.onthegomap.planetiler.geo.GeometryPipeline;
89
import com.onthegomap.planetiler.geo.GeometryType;
910
import com.onthegomap.planetiler.geo.SimplifyMethod;
1011
import com.onthegomap.planetiler.reader.SourceFeature;
@@ -506,6 +507,9 @@ public final class Feature implements WithZoomRange<Feature>, WithAttrs<Feature>
506507
private SimplifyMethod defaultSimplifyMethod = SimplifyMethod.DOUGLAS_PEUCKER;
507508
private ZoomFunction<SimplifyMethod> simplifyMethod = null;
508509

510+
private GeometryPipeline defaultGeometryPipeline = null;
511+
private ZoomFunction<GeometryPipeline> geometryPipelineByZoom = null;
512+
509513
private String numPointsAttr = null;
510514
private List<OverrideCommand> partialOverrides = null;
511515

@@ -740,6 +744,40 @@ public SimplifyMethod getSimplifyMethodAtZoom(int zoom) {
740744
return ZoomFunction.applyOrElse(simplifyMethod, zoom, defaultSimplifyMethod);
741745
}
742746

747+
/**
748+
* Sets the default pipeline to apply to geometries scaled to tile coordinates right before emitting vector tile
749+
* features. This function gets run instead of simplification, so should include any simplification if you want
750+
* that.
751+
* <p>
752+
* Geometries will be in scaled tile coordinates, so {@code 0,0} is the northwest corner and {@code 2^z, 2^z} is the
753+
* southeast corner of the world scaled to web mercator coordinates.
754+
*/
755+
public Feature transformScaledGeometry(GeometryPipeline pipeline) {
756+
this.defaultGeometryPipeline = pipeline;
757+
return this;
758+
}
759+
760+
/**
761+
* Dynamically change the geometry pipeline to apply to geometries scaled to tile coordinates right before emitting
762+
* vector tile features at each zoom level. These functions get run instead of simplification, so should include any
763+
* simplification if you want that.
764+
* <p>
765+
* Geometries will be in scaled tile coordinates, so {@code 0,0} is the northwest corner and {@code 2^z, 2^z} is the
766+
* southeast corner of the world scaled to web mercator coordinates.
767+
*/
768+
public Feature transformScaledGeometryByZoom(ZoomFunction<GeometryPipeline> overrides) {
769+
this.geometryPipelineByZoom = overrides;
770+
return this;
771+
}
772+
773+
/**
774+
* Returns the geometry transform function to apply to scaled geometries at {@code zoom}, or null to not update them
775+
* at all.
776+
*/
777+
public GeometryPipeline getScaledGeometryTransformAtZoom(int zoom) {
778+
return ZoomFunction.applyOrElse(geometryPipelineByZoom, zoom, defaultGeometryPipeline);
779+
}
780+
743781
/**
744782
* Sets the simplification tolerance for lines and polygons in tile pixels below the maximum zoom-level of the map.
745783
* <p>
@@ -1091,6 +1129,10 @@ Partial withAttr(String key, Object value) {
10911129
return rangesWithGeometries;
10921130
}
10931131

1132+
public SourceFeature source() {
1133+
return source;
1134+
}
1135+
10941136

10951137
/**
10961138
* A builder that can be used to configure linear-scoped attributes for a partial segment of a line feature.

planetiler-core/src/main/java/com/onthegomap/planetiler/FeatureMerge.java

+29-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.onthegomap.planetiler.collection.Hppc;
77
import com.onthegomap.planetiler.geo.GeoUtils;
88
import com.onthegomap.planetiler.geo.GeometryException;
9+
import com.onthegomap.planetiler.geo.GeometryPipeline;
910
import com.onthegomap.planetiler.geo.GeometryType;
1011
import com.onthegomap.planetiler.geo.MutableCoordinateSequence;
1112
import com.onthegomap.planetiler.stats.DefaultStats;
@@ -81,7 +82,7 @@ private FeatureMerge() {}
8182
*/
8283
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
8384
double minLength, double tolerance, double buffer, boolean resimplify) {
84-
return mergeLineStrings(features, attrs -> minLength, tolerance, buffer, resimplify);
85+
return mergeLineStrings(features, attrs -> minLength, tolerance, buffer, resimplify, null);
8586
}
8687

8788
/**
@@ -143,20 +144,22 @@ private static List<VectorTile.Feature> mergeGeometries(
143144
}
144145

145146
/**
146-
* Merges linestrings with the same attributes as {@link #mergeLineStrings(List, Function, double, double, boolean)}
147-
* except sets {@code resimplify=false} by default.
147+
* Merges linestrings with the same attributes as
148+
* {@link #mergeLineStrings(List, Function, double, double, boolean, GeometryPipeline)} except sets
149+
* {@code resimplify=false} by default.
148150
*/
149151
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
150152
Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer) {
151-
return mergeLineStrings(features, lengthLimitCalculator, tolerance, buffer, false);
153+
return mergeLineStrings(features, lengthLimitCalculator, tolerance, buffer, false, null);
152154
}
153155

154156
/**
155157
* Merges linestrings with the same attributes as {@link #mergeLineStrings(List, double, double, double, boolean)}
156158
* except with a dynamic length limit computed by {@code lengthLimitCalculator} for the attributes of each group.
157159
*/
158160
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
159-
Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer, boolean resimplify) {
161+
Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer, boolean resimplify,
162+
GeometryPipeline pipeline) {
160163
List<VectorTile.Feature> result = new ArrayList<>(features.size());
161164
var groupedByAttrs = groupByAttrs(features, result, GeometryType.LINE);
162165
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
@@ -176,7 +179,8 @@ public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature>
176179
.setMergeStrokes(true)
177180
.setMinLength(lengthLimit)
178181
.setLoopMinLength(lengthLimit)
179-
.setStubMinLength(0.5);
182+
.setStubMinLength(0.5)
183+
.setSegmentTransform(pipeline);
180184
for (VectorTile.Feature feature : groupedFeatures) {
181185
try {
182186
merger.add(feature.geometry().decode());
@@ -287,12 +291,15 @@ public static List<VectorTile.Feature> mergeOverlappingPolygons(List<VectorTile.
287291
* @param buffer the amount (in tile pixels) to expand then contract polygons by in order to combine
288292
* almost-touching polygons
289293
* @param stats for counting data errors
294+
* @param pipeline a transform that should be applied to each merged polygon in tile pixel coordinates where
295+
* {@code 0,0} is the top-left and {@code 256,256} is the bottom-right corner of the tile
290296
* @return a new list containing all unaltered features in their original order, then each of the merged groups
291297
* ordered by the index of the first element in that group from the input list.
292298
* @throws GeometryException if an error occurs encoding the combined geometry
293299
*/
294300
public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Feature> features, double minArea,
295-
double minHoleArea, double minDist, double buffer, Stats stats) throws GeometryException {
301+
double minHoleArea, double minDist, double buffer, Stats stats, GeometryPipeline pipeline)
302+
throws GeometryException {
296303
List<VectorTile.Feature> result = new ArrayList<>(features.size());
297304
Collection<List<VectorTile.Feature>> groupedByAttrs = groupByAttrs(features, result, GeometryType.POLYGON);
298305
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
@@ -326,12 +333,26 @@ public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Featu
326333
if (!(merged instanceof Polygonal) || merged.getEnvelopeInternal().getArea() < minArea) {
327334
continue;
328335
}
336+
if (pipeline != null) {
337+
merged = pipeline.apply(merged);
338+
if (!(merged instanceof Polygonal)) {
339+
continue;
340+
}
341+
}
329342
merged = GeoUtils.snapAndFixPolygon(merged, stats, "merge").reverse();
330343
} else {
331344
merged = polygonGroup.getFirst();
332345
if (!(merged instanceof Polygonal) || merged.getEnvelopeInternal().getArea() < minArea) {
333346
continue;
334347
}
348+
if (pipeline != null) {
349+
Geometry after = pipeline.apply(merged);
350+
if (!(after instanceof Polygonal)) {
351+
continue;
352+
} else if (after != merged) {
353+
merged = GeoUtils.snapAndFixPolygon(after, stats, "merge_after_pipeline").reverse();
354+
}
355+
}
335356
}
336357
extractPolygons(merged, outPolygons, minArea, minHoleArea);
337358
}
@@ -354,7 +375,7 @@ private static <G extends Geometry> List<G> sortByHilbertIndex(List<G> geometrie
354375

355376
public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Feature> features, double minArea,
356377
double minHoleArea, double minDist, double buffer) throws GeometryException {
357-
return mergeNearbyPolygons(features, minArea, minHoleArea, minDist, buffer, DefaultStats.get());
378+
return mergeNearbyPolygons(features, minArea, minHoleArea, minDist, buffer, DefaultStats.get(), null);
358379
}
359380

360381

0 commit comments

Comments
 (0)