Min polygon area centroid (#720)

pull/721/head
Michael Barry 2023-11-13 07:16:55 -05:00 zatwierdzone przez GitHub
rodzic c4036f317a
commit ec6430dc49
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 122 dodań i 2 usunięć

Wyświetl plik

@ -230,6 +230,10 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
this.geom = geom;
this.geometryType = GeometryType.typeOf(geom);
this.id = id;
if (geometryType == GeometryType.POINT) {
minPixelSizeAtMaxZoom = 0;
defaultMinPixelSize = 0;
}
}
/** Returns the original ID of the source feature that this feature came from (i.e. OSM node/way ID). */
@ -728,5 +732,15 @@ public class FeatureCollector implements Iterable<FeatureCollector.Feature> {
", attrs=" + attrs +
'}';
}
/** Returns the actual pixel size of the source feature at {@code zoom} (length if line, sqrt(area) if polygon). */
public double getSourceFeaturePixelSizeAtZoom(int zoom) {
try {
return source.size() * (256 << zoom);
} catch (GeometryException e) {
e.log(stats, "point_get_size_failure", "Error getting min size for point from geometry " + source.id());
return 0;
}
}
}
}

Wyświetl plik

@ -39,6 +39,7 @@ public abstract class SourceFeature implements WithTags, WithGeometryType {
private Geometry validPolygon = null;
private double area = Double.NaN;
private double length = Double.NaN;
private double size = Double.NaN;
/**
* Constructs a new input feature.
@ -245,6 +246,14 @@ public abstract class SourceFeature implements WithTags, WithGeometryType {
(isPoint() || canBePolygon() || canBeLine()) ? worldGeometry().getLength() : 0) : length;
}
/**
* Returns and caches sqrt of {@link #area()} if polygon or {@link #length()} if a line string.
*/
public double size() throws GeometryException {
return Double.isNaN(size) ? (size = canBePolygon() ? Math.sqrt(Math.abs(area())) : canBeLine() ? length() : 0) :
size;
}
/** Returns the ID of the source that this feature came from. */
public String getSource() {
return source;
@ -292,4 +301,5 @@ public abstract class SourceFeature implements WithTags, WithGeometryType {
public boolean hasRelationInfo() {
return relationInfos != null && !relationInfos.isEmpty();
}
}

Wyświetl plik

@ -97,6 +97,10 @@ public class FeatureRenderer implements Consumer<FeatureCollector.Feature>, Clos
coords[i] = origCoords[i].copy();
}
for (int zoom = feature.getMaxZoom(); zoom >= feature.getMinZoom(); zoom--) {
double minSize = feature.getMinPixelSizeAtZoom(zoom);
if (minSize > 0 && feature.getSourceFeaturePixelSizeAtZoom(zoom) < minSize) {
continue;
}
Map<String, Object> attrs = feature.getAttrsAtZoom(zoom);
double buffer = feature.getBufferPixelsAtZoom(zoom) / 256;
int tilesAtZoom = 1 << zoom;
@ -207,7 +211,7 @@ public class FeatureRenderer implements Consumer<FeatureCollector.Feature>, Clos
}
Map<String, Object> attrs = feature.getAttrsAtZoom(sliced.zoomLevel());
if (numPointsAttr != null) {
// if profile wants the original number of points that the simplified but untiled geometry started with
// if profile wants the original number off points that the simplified but untiled geometry started with
attrs = new HashMap<>(attrs);
attrs.put(numPointsAttr, geom.getNumPoints());
}

Wyświetl plik

@ -614,5 +614,4 @@ class FeatureCollectorTest {
)
), collector);
}
}

Wyświetl plik

@ -592,6 +592,15 @@ class PlanetilerTests {
return points;
}
public List<Coordinate> z14PixelRectangle(double min, double max) {
List<Coordinate> points = rectangleCoordList(min / 256d, max / 256d);
points.forEach(c -> {
c.x = GeoUtils.getWorldLon(0.5 + c.x * Z14_WIDTH);
c.y = GeoUtils.getWorldLat(0.5 + c.y * Z14_WIDTH);
});
return points;
}
public List<Coordinate> z14CoordinatePixelList(double... coords) {
return z14CoordinateList(DoubleStream.of(coords).map(c -> c / 256d).toArray());
}
@ -2341,6 +2350,90 @@ class PlanetilerTests {
assertEquals(bboxResult.tiles, polyResult.tiles);
}
@Test
void testSimplePolygon() throws Exception {
List<Coordinate> points = z14PixelRectangle(0, 40);
var results = runWithReaderFeatures(
Map.of("threads", "1"),
List.of(
newReaderFeature(newPolygon(points), Map.of())
),
(in, features) -> features.polygon("layer")
.setZoomRange(0, 14)
.setBufferPixels(0)
.setMinPixelSize(10) // should only show up z14 (40) z13 (20) and z12 (10)
);
assertEquals(Map.ofEntries(
newTileEntry(Z12_TILES / 2, Z12_TILES / 2, 12, List.of(
feature(newPolygon(rectangleCoordList(0, 10)), Map.of())
)),
newTileEntry(Z13_TILES / 2, Z13_TILES / 2, 13, List.of(
feature(newPolygon(rectangleCoordList(0, 20)), Map.of())
)),
newTileEntry(Z14_TILES / 2, Z14_TILES / 2, 14, List.of(
feature(newPolygon(rectangleCoordList(0, 40)), Map.of())
))
), results.tiles);
}
@Test
void testCentroidWithPolygonMinSize() throws Exception {
List<Coordinate> points = z14PixelRectangle(0, 40);
var results = runWithReaderFeatures(
Map.of("threads", "1"),
List.of(
newReaderFeature(newPolygon(points), Map.of())
),
(in, features) -> features.centroid("layer")
.setZoomRange(0, 14)
.setBufferPixels(0)
.setMinPixelSize(10) // should only show up z14 (40) z13 (20) and z12 (10)
);
assertEquals(Map.ofEntries(
newTileEntry(Z12_TILES / 2, Z12_TILES / 2, 12, List.of(
feature(newPoint(5, 5), Map.of())
)),
newTileEntry(Z13_TILES / 2, Z13_TILES / 2, 13, List.of(
feature(newPoint(10, 10), Map.of())
)),
newTileEntry(Z14_TILES / 2, Z14_TILES / 2, 14, List.of(
feature(newPoint(20, 20), Map.of())
))
), results.tiles);
}
@Test
void testCentroidWithLineMinSize() throws Exception {
List<Coordinate> points = z14CoordinatePixelList(0, 4, 40, 4);
var results = runWithReaderFeatures(
Map.of("threads", "1"),
List.of(
newReaderFeature(newLineString(points), Map.of())
),
(in, features) -> features.centroid("layer")
.setZoomRange(0, 14)
.setBufferPixels(0)
.setMinPixelSize(10) // should only show up z14 (40) z13 (20) and z12 (10)
);
assertEquals(Map.ofEntries(
newTileEntry(Z12_TILES / 2, Z12_TILES / 2, 12, List.of(
feature(newPoint(5, 1), Map.of())
)),
newTileEntry(Z13_TILES / 2, Z13_TILES / 2, 13, List.of(
feature(newPoint(10, 2), Map.of())
)),
newTileEntry(Z14_TILES / 2, Z14_TILES / 2, 14, List.of(
feature(newPoint(20, 4), Map.of())
))
), results.tiles);
}
@Test
void testBoundFiltersFill() throws Exception {
var polyResultz8 = runForBoundsTest(8, 8, "polygon", TestUtils.pathToResource("bottomrightearth.poly").toString());