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

GeometryPipeline #1118

Merged
merged 23 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.geo.GeoUtils;
import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.geo.GeometryPipeline;
import com.onthegomap.planetiler.geo.GeometryType;
import com.onthegomap.planetiler.geo.SimplifyMethod;
import com.onthegomap.planetiler.reader.SourceFeature;
Expand Down Expand Up @@ -506,6 +507,9 @@ public final class Feature implements WithZoomRange<Feature>, WithAttrs<Feature>
private SimplifyMethod defaultSimplifyMethod = SimplifyMethod.DOUGLAS_PEUCKER;
private ZoomFunction<SimplifyMethod> simplifyMethod = null;

private GeometryPipeline defaultGeometryPipeline = null;
private ZoomFunction<GeometryPipeline> geometryPipelineByZoom = null;

private String numPointsAttr = null;
private List<OverrideCommand> partialOverrides = null;

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

/**
* Sets the default pipeline to apply to geometries scaled to tile coordinates right before emitting vector tile
* features. This function gets run instead of simplification, so should include any simplification if you want
* that.
* <p>
* Geometries will be in scaled tile coordinates, so {@code 0,0} is the northwest corner and {@code 2^z, 2^z} is the
* southeast corner of the world scaled to web mercator coordinates.
*/
public Feature transformScaledGeometry(GeometryPipeline pipeline) {
this.defaultGeometryPipeline = pipeline;
return this;
}

/**
* Dynamically change the geometry pipeline to apply to geometries scaled to tile coordinates right before emitting
* vector tile features at each zoom level. These functions get run instead of simplification, so should include any
* simplification if you want that.
* <p>
* Geometries will be in scaled tile coordinates, so {@code 0,0} is the northwest corner and {@code 2^z, 2^z} is the
* southeast corner of the world scaled to web mercator coordinates.
*/
public Feature transformScaledGeometryByZoom(ZoomFunction<GeometryPipeline> overrides) {
this.geometryPipelineByZoom = overrides;
return this;
}

/**
* Returns the geometry transform function to apply to scaled geometries at {@code zoom}, or null to not update them
* at all.
*/
public GeometryPipeline getScaledGeometryTransformAtZoom(int zoom) {
return ZoomFunction.applyOrElse(geometryPipelineByZoom, zoom, defaultGeometryPipeline);
}

/**
* Sets the simplification tolerance for lines and polygons in tile pixels below the maximum zoom-level of the map.
* <p>
Expand Down Expand Up @@ -1091,6 +1129,10 @@ Partial withAttr(String key, Object value) {
return rangesWithGeometries;
}

public SourceFeature source() {
return source;
}


/**
* A builder that can be used to configure linear-scoped attributes for a partial segment of a line feature.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.onthegomap.planetiler.collection.Hppc;
import com.onthegomap.planetiler.geo.GeoUtils;
import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.geo.GeometryPipeline;
import com.onthegomap.planetiler.geo.GeometryType;
import com.onthegomap.planetiler.geo.MutableCoordinateSequence;
import com.onthegomap.planetiler.stats.DefaultStats;
Expand Down Expand Up @@ -81,7 +82,7 @@
*/
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
double minLength, double tolerance, double buffer, boolean resimplify) {
return mergeLineStrings(features, attrs -> minLength, tolerance, buffer, resimplify);
return mergeLineStrings(features, attrs -> minLength, tolerance, buffer, resimplify, null);
}

/**
Expand Down Expand Up @@ -143,20 +144,22 @@
}

/**
* Merges linestrings with the same attributes as {@link #mergeLineStrings(List, Function, double, double, boolean)}
* except sets {@code resimplify=false} by default.
* Merges linestrings with the same attributes as
* {@link #mergeLineStrings(List, Function, double, double, boolean, GeometryPipeline)} except sets
* {@code resimplify=false} by default.
*/
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer) {
return mergeLineStrings(features, lengthLimitCalculator, tolerance, buffer, false);
return mergeLineStrings(features, lengthLimitCalculator, tolerance, buffer, false, null);
}

/**
* Merges linestrings with the same attributes as {@link #mergeLineStrings(List, double, double, double, boolean)}
* except with a dynamic length limit computed by {@code lengthLimitCalculator} for the attributes of each group.
*/
public static List<VectorTile.Feature> mergeLineStrings(List<VectorTile.Feature> features,
Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer, boolean resimplify) {
Function<Map<String, Object>, Double> lengthLimitCalculator, double tolerance, double buffer, boolean resimplify,

Check warning on line 161 in planetiler-core/src/main/java/com/onthegomap/planetiler/FeatureMerge.java

View workflow job for this annotation

GitHub Actions / Analyze with Sonar

MINOR CODE_SMELL

Refactor this code to use the more specialised Functional Interface 'ToDoubleFunction<Map>' rule: java:S4276 (https://sonarcloud.io/organizations/onthegomap/rules?open=java%3AS4276&rule_key=java%3AS4276) issue url: https://sonarcloud.io/project/issues?pullRequest=1118&open=AZOb6fhCvuTsgZ3mwcyi&id=onthegomap_planetiler
GeometryPipeline pipeline) {
List<VectorTile.Feature> result = new ArrayList<>(features.size());
var groupedByAttrs = groupByAttrs(features, result, GeometryType.LINE);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
Expand All @@ -176,7 +179,8 @@
.setMergeStrokes(true)
.setMinLength(lengthLimit)
.setLoopMinLength(lengthLimit)
.setStubMinLength(0.5);
.setStubMinLength(0.5)
.setSegmentTransform(pipeline);
for (VectorTile.Feature feature : groupedFeatures) {
try {
merger.add(feature.geometry().decode());
Expand Down Expand Up @@ -287,12 +291,15 @@
* @param buffer the amount (in tile pixels) to expand then contract polygons by in order to combine
* almost-touching polygons
* @param stats for counting data errors
* @param pipeline a transform that should be applied to each merged polygon in tile pixel coordinates where
* {@code 0,0} is the top-left and {@code 256,256} is the bottom-right corner of the tile
* @return a new list containing all unaltered features in their original order, then each of the merged groups
* ordered by the index of the first element in that group from the input list.
* @throws GeometryException if an error occurs encoding the combined geometry
*/
public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Feature> features, double minArea,
double minHoleArea, double minDist, double buffer, Stats stats) throws GeometryException {
double minHoleArea, double minDist, double buffer, Stats stats, GeometryPipeline pipeline)
throws GeometryException {
List<VectorTile.Feature> result = new ArrayList<>(features.size());
Collection<List<VectorTile.Feature>> groupedByAttrs = groupByAttrs(features, result, GeometryType.POLYGON);
for (List<VectorTile.Feature> groupedFeatures : groupedByAttrs) {
Expand Down Expand Up @@ -326,12 +333,26 @@
if (!(merged instanceof Polygonal) || merged.getEnvelopeInternal().getArea() < minArea) {
continue;
}
if (pipeline != null) {
merged = pipeline.apply(merged);
if (!(merged instanceof Polygonal)) {
continue;
}
}
merged = GeoUtils.snapAndFixPolygon(merged, stats, "merge").reverse();
} else {
merged = polygonGroup.getFirst();
if (!(merged instanceof Polygonal) || merged.getEnvelopeInternal().getArea() < minArea) {
continue;
}
if (pipeline != null) {
Geometry after = pipeline.apply(merged);
if (!(after instanceof Polygonal)) {
continue;
} else if (after != merged) {
merged = GeoUtils.snapAndFixPolygon(after, stats, "merge_after_pipeline").reverse();
}
}
}
extractPolygons(merged, outPolygons, minArea, minHoleArea);
}
Expand All @@ -354,7 +375,7 @@

public static List<VectorTile.Feature> mergeNearbyPolygons(List<VectorTile.Feature> features, double minArea,
double minHoleArea, double minDist, double buffer) throws GeometryException {
return mergeNearbyPolygons(features, minArea, minHoleArea, minDist, buffer, DefaultStats.get());
return mergeNearbyPolygons(features, minArea, minHoleArea, minDist, buffer, DefaultStats.get(), null);
}


Expand Down
Loading
Loading