Skip to content

Commit

Permalink
tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
msbarry committed Dec 2, 2024
1 parent 70549a0 commit 8565237
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ public SimplifyMethod getSimplifyMethodAtZoom(int zoom) {
* features. This function gets run instead of simplification, so should include any simplification if you want
* that.
*/
public Feature setGeometryPipeline(GeometryPipeline pipeline) {
public Feature transformScaledGeometry(GeometryPipeline pipeline) {
this.defaultGeometryPipeline = pipeline;
return this;
}
Expand All @@ -759,7 +759,7 @@ public Feature setGeometryPipeline(GeometryPipeline pipeline) {
* vector tile features. These functions get run instead of simplification, so should include any simplification if
* you want that.
*/
public Feature setGeometryPipelineByZoom(ZoomFunction<GeometryPipeline> overrides) {
public Feature transformScaledGeometryByZoom(ZoomFunction<GeometryPipeline> overrides) {
this.geometryPipelineByZoom = overrides;
return this;
}
Expand All @@ -768,7 +768,7 @@ public Feature setGeometryPipelineByZoom(ZoomFunction<GeometryPipeline> override
* Returns the geometry transform function to apply to scaled geometries at {@code zoom}, or null to not update them
* at all.
*/
public GeometryPipeline getGeometryPipelineAtZoom(int zoom) {
public GeometryPipeline getScaledGeometryTransformAtZoom(int zoom) {
return ZoomFunction.applyOrElse(geometryPipelineByZoom, zoom, defaultGeometryPipeline);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
import com.onthegomap.planetiler.util.ZoomFunction;
import org.locationtech.jts.geom.Geometry;

/**
* A function that transforms a {@link Geometry}.
* <p>
* This can be chained and used in {@link FeatureCollector.Feature#transformScaledGeometry(GeometryPipeline)} to
* transform geometries before slicing them into tiles.
*/
@FunctionalInterface
public interface GeometryPipeline extends ZoomFunction<GeometryPipeline> {
GeometryPipeline NOOP = g -> g;
Expand All @@ -16,6 +22,7 @@ default GeometryPipeline apply(int zoom) {
return this;
}

/** Returns a function equivalent to {@code other(this(geom))}. */
default GeometryPipeline andThen(GeometryPipeline other) {
return input -> other.apply(apply(input));
}
Expand Down Expand Up @@ -94,4 +101,20 @@ static VWSimplifier simplifyVW(double tolerance) {
static DouglasPeuckerSimplifier simplifyDP(double tolerance) {
return new DouglasPeuckerSimplifier(tolerance);
}

/**
* Returns a pipeline that smoothes an input geometry by joining the midpoint of each edge of lines or polygons in the
* order in which they are encountered.
*/
static MidpointSmoother smoothMidpoint() {
return MidpointSmoother.midpoint();
}

/**
* Returns a pipeline that smoothes an input geometry by slicing off each corner {@code iters} times until you get a
* sufficiently smooth curve.
*/
static MidpointSmoother smoothChaikin(int iters) {
return MidpointSmoother.chaikin(iters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,45 @@
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.util.GeometryTransformer;

/**
* Smoothes an input geometry by interpolating points along each edge and repeating for a set number of iterations.
* <p>
* When the points array is {@code [0.5]} this means midpoint smoothing, and when it is {@code [0.25, 0.75]} it means
* <a href="https://observablehq.com/@pamacha/chaikins-algorithm">Chaikin Smoothing</a>.
*/
public class MidpointSmoother extends GeometryTransformer implements GeometryPipeline {

private static final double[] CHAIKIN = new double[]{0.25, 0.75};
private static final double[] MIDPOINT = new double[]{0.5};
private final double[] points;
private int iters = 1;
private boolean includeLineEndpoints = true;

public MidpointSmoother(double[] points) {
this.points = points;
}

@Override
public Geometry apply(Geometry input) {
return transform(input);
/**
* Returns a new smoother that does <a href="https://observablehq.com/@pamacha/chaikins-algorithm">Chaikin
* Smoothing</a> {@code iters} times on the input line.
*/
public static MidpointSmoother chaikin(int iters) {
return new MidpointSmoother(CHAIKIN).setIters(iters);
}

/** Returns a new smoother that does midpoint smoothing. */
public static MidpointSmoother midpoint() {
return new MidpointSmoother(MIDPOINT);
}

/** Sets the number of times that smoothing runs. */
public MidpointSmoother setIters(int iters) {
this.iters = iters;
return this;
}

public MidpointSmoother includeLineEndpoints(boolean includeLineEndpoints) {
this.includeLineEndpoints = includeLineEndpoints;
return this;
@Override
public Geometry apply(Geometry input) {
return transform(input);
}

@Override
Expand All @@ -38,8 +54,8 @@ protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geo
}
for (int iter = 0; iter < iters; iter++) {
MutableCoordinateSequence result = new MutableCoordinateSequence();
boolean skipFirstAndLastInterpolated = !area && includeLineEndpoints && points.length > 1;
if (!area && includeLineEndpoints) {
boolean skipFirstAndLastInterpolated = !area && points.length > 1;
if (!area) {
result.addPoint(coords.getX(0), coords.getY(0));
}
int last = coords.size() - 1;
Expand All @@ -54,18 +70,17 @@ protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geo
double dx = x2 - x1;
double dy = y2 - y1;
for (int j = 0; j < points.length; j++) {
if (skipFirstAndLastInterpolated) {
if ((i == 0 && j == 0) || (i == last - 1 && j == points.length - 1)) {
continue;
}
if (skipFirstAndLastInterpolated && ((i == 0 && j == 0) || (i == last - 1 && j == points.length - 1))) {
continue;
}

double value = points[j];
result.addPoint(x1 + dx * value, y1 + dy * value);
}
}
if (area) {
result.closeRing();
} else if (includeLineEndpoints) {
} else {
result.addPoint(coords.getX(last), coords.getY(last));
}
coords = result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void accept(FeatureCollector.Feature feature) {
private void accept(int zoom, Geometry geom, Map<String, Object> attrs, FeatureCollector.Feature feature) {
double scale = 1 << zoom;
geom = AffineTransformation.scaleInstance(scale, scale).transform(geom);
GeometryPipeline pipeline = feature.getGeometryPipelineAtZoom(zoom);
GeometryPipeline pipeline = feature.getScaledGeometryTransformAtZoom(zoom);
if (pipeline != null) {
geom = pipeline.apply(geom);
} else if (!(geom instanceof Puntal)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,35 +65,4 @@ void testMultiPassSmooth(String inWKT, String outWKT) throws ParseException {
TestUtils.round(new MidpointSmoother(new double[]{0.2, 0.8}).setIters(2).apply(in))
);
}

@ParameterizedTest
@CsvSource(value = {
"POINT(1 1); POINT(1 1)",
"LINESTRING(0 0, 10 10); LINESTRING(0 0, 10 10)",
"LINESTRING(0 0, 10 0, 10 10); LINESTRING(5 0, 10 5)",
"LINESTRING(0 0, 10 0, 10 10, 0 10); LINESTRING(5 0, 10 5, 5 10)",
}, delimiter = ';')
void testDontIncludeEndpointsMidpoint(String inWKT, String outWKT) throws ParseException {
var reader = new WKTReader();
assertEquals(
TestUtils.round(reader.read(outWKT)),
TestUtils.round(
new MidpointSmoother(new double[]{0.5}).setIters(1).includeLineEndpoints(false).apply(reader.read(inWKT)))
);
}

@ParameterizedTest
@CsvSource(value = {
"LINESTRING(0 0, 10 10); LINESTRING(0 0, 10 10)",
"LINESTRING(0 0, 10 0, 10 10); LINESTRING(2 0, 8 0, 10 2, 10 8)",
"LINESTRING(0 0, 10 0, 10 10, 0 10); LINESTRING(2 0, 8 0, 10 2, 10 8, 8 10, 2 10)",
}, delimiter = ';')
void testDontIncludeEndpointsDualMidpoint(String inWKT, String outWKT) throws ParseException {
var reader = new WKTReader();
assertEquals(
TestUtils.round(reader.read(outWKT)),
TestUtils.round(
new MidpointSmoother(new double[]{0.2, 0.8}).setIters(1).includeLineEndpoints(false).apply(reader.read(inWKT)))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1510,7 +1510,7 @@ void testGeometryPipeline() {
0.5 + Z14_WIDTH / 2, 0.5 + Z14_WIDTH / 2,
0.5 + Z14_WIDTH / 2 + Z14_PX * 10, 0.5 + Z14_WIDTH / 2
)
).setGeometryPipeline(Geometry::getCentroid).setAttr("k", "v");
).transformScaledGeometry(Geometry::getCentroid).setAttr("k", "v");
assertEquals(
Set.of(
List.of(newPoint(128 + 5, 128), Map.of("k", "v"))
Expand All @@ -1526,7 +1526,7 @@ void testGeometryPipelineSimplify() {
0.5 + Z14_WIDTH / 2, 0.5 + Z14_WIDTH / 2,
0.5 + Z14_WIDTH / 2 + Z14_PX * 10, 0.5 + Z14_WIDTH / 2
)
).setGeometryPipeline(
).transformScaledGeometry(
GeometryPipeline.simplifyVW(1).setWeight(0.9)
.andThen(GeometryPipeline.simplifyDP(1))
).setAttr("k", "v");
Expand Down

0 comments on commit 8565237

Please sign in to comment.