From bee87bdab2dcc77a7bb306bddc314ad212f00363 Mon Sep 17 00:00:00 2001 From: Erica Fischer Date: Mon, 13 Nov 2023 22:16:37 -0800 Subject: [PATCH] Limit decay into polygon dust to reasonably compact polygons --- geometry.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/geometry.cpp b/geometry.cpp index 07ff1529..5c7f75b9 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -176,6 +176,18 @@ void check_polygon(drawvec &geom) { } } +double get_perimeter(const drawvec &geom, size_t i, size_t j) { + double perimeter = 0; + + for (size_t k = i; k + 1 < j; k++) { + double dx = geom[k].x - geom[k + 1].x; + double dy = geom[k].y - geom[k + 1].y; + perimeter += sqrt(dx * dx + dy * dy); + } + + return perimeter; +} + drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *still_needs_simplification, bool *reduced_away, double *accum_area, serial_feature *this_feature, serial_feature *tiny_feature) { drawvec out; const double pixel = (1LL << (32 - detail - z)) * (double) tiny_polygon_size; @@ -196,6 +208,17 @@ drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *still_needs_sim } double area = get_area(geom, i, j); + double schwartzberg = 1; + + if (area != 0) { + // polygon compactness measure + // https://fisherzachary.github.io/public/r-output.html + // Schwartzberg, Joseph E. 1965. “Reapportionment, gerrymanders, and the notion of compactness”. + // In: Minn. L. Rev. 50, 443. + + double perimeter = get_perimeter(geom, i, j); + schwartzberg = 1 / (perimeter / (2 * M_PI * sqrt(std::fabs(area) / M_PI))); + } // XXX There is an ambiguity here: If the area of a ring is 0 and it is followed by holes, // we don't know whether the area-0 ring was a hole too or whether it was the outer ring @@ -213,7 +236,8 @@ drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *still_needs_sim // OR it is an inner ring and we haven't output an outer ring for it to be // cut out of, so we are just subtracting its area from the tiny polygon // rather than trying to deal with it geometrically - if ((area > 0 && area <= pixel * pixel) || (area < 0 && !included_last_outer)) { + if ((area > 0 && area <= pixel * pixel && schwartzberg > 0.3) || + (area < 0 && !included_last_outer)) { *accum_area += area; *reduced_away = true;