Skip to content

Commit

Permalink
Don't try to revive continous polygons if they collapse away
Browse files Browse the repository at this point in the history
  • Loading branch information
e-n-f committed Oct 20, 2023
1 parent a1ce734 commit 67cb8c5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 21 deletions.
60 changes: 43 additions & 17 deletions geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "errors.hpp"
#include "projection.hpp"

bool is_shared_node(draw d, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos);

drawvec decode_geometry(char **meta, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y) {
drawvec out;

Expand Down Expand Up @@ -176,7 +178,28 @@ void check_polygon(drawvec &geom) {
}
}

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) {
bool can_be_dust(drawvec const &geom, size_t i, size_t j, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos) {
if (!prevent[P_SIMPLIFY_SHARED_NODES]) {
return true;
}

size_t count = 0;
for (; i < j; i++) {
if (is_shared_node(geom[i], z, tx, ty, shared_nodes_map, nodepos)) {
count++;

if (count >= 4) {
// the three fixed nodes of this feature,
// plus some intersection with some other feature
return false;
}
}
}

return true;
}

drawvec reduce_tiny_poly(drawvec &geom, int z, int tx, int ty, int detail, bool *still_needs_simplification, bool *reduced_away, double *accum_area, serial_feature *this_feature, serial_feature *tiny_feature, struct node *shared_nodes_map, size_t nodepos) {
drawvec out;
const double pixel = (1LL << (32 - detail - z)) * (double) tiny_polygon_size;
bool includes_real = false;
Expand Down Expand Up @@ -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 (can_be_dust(geom, i, j, z, tx, ty, shared_nodes_map, nodepos) &&
((area > 0 && area <= pixel * pixel) || (area < 0 && !included_last_outer))) {
*accum_area += area;
*reduced_away = true;

Expand Down Expand Up @@ -485,20 +509,7 @@ drawvec impose_tile_boundaries(drawvec &geom, long long extent) {
return out;
}

bool is_shared_node(draw d, int z, int tx, int ty, drawvec const &shared_nodes, struct node *shared_nodes_map, size_t nodepos) {
// This is kind of weird, because we have two lists of shared nodes to look through:
// * the drawvec, which is nodes that were introduced during clipping to the tile edge,
// and which are in local tile coordinates
// * the shared_nodes_map, which was made globally before tiling began, and which
// is in global quadkey coordinates.
// To look through the latter, we need to offset and encode the coordinates
// of the feature we are simplifying.

auto pt = std::lower_bound(shared_nodes.begin(), shared_nodes.end(), d);
if (pt != shared_nodes.end() && *pt == d) {
return true;
}

bool is_shared_node(draw d, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos) {
if (nodepos > 0) {
// offset to global
if (z != 0) {
Expand Down Expand Up @@ -534,7 +545,22 @@ drawvec simplify_lines(drawvec &geom, int z, int tx, int ty, int detail, bool ma
}

if (prevent[P_SIMPLIFY_SHARED_NODES]) {
if (is_shared_node(geom[i], z, tx, ty, shared_nodes, shared_nodes_map, nodepos)) {
// This is kind of weird, because we have two lists of shared nodes to look through:
// * the drawvec, which is nodes that were introduced during clipping to the tile edge,
// and which are in local tile coordinates
// * the shared_nodes_map, which was made globally before tiling began, and which
// is in global quadkey coordinates.
// To look through the latter, we need to offset and encode the coordinates
// of the feature we are simplifying.

// nodes introduced at the tile edge
auto pt = std::lower_bound(shared_nodes.begin(), shared_nodes.end(), geom[i]);
if (pt != shared_nodes.end() && *pt == geom[i]) {
geom[i].necessary = true;
}

// global shared nodes
if (is_shared_node(geom[i], z, tx, ty, shared_nodes_map, nodepos)) {
geom[i].necessary = true;
}
}
Expand Down
3 changes: 2 additions & 1 deletion geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ drawvec remove_noop(drawvec geom, int type, int shift);
drawvec clip_point(drawvec &geom, int z, long long buffer);
drawvec clean_or_clip_poly(drawvec &geom, int z, int buffer, bool clip, bool try_scaling);
drawvec close_poly(drawvec &geom);
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 reduce_tiny_poly(drawvec &geom, int z, int tx, int ty, int detail, bool *still_needs_simplification, bool *reduced_away, double *accum_area, serial_feature *this_feature, serial_feature *tiny_feature, struct node *shared_nodes_map, size_t nodepos);
int clip(long long *x0, long long *y0, long long *x1, long long *y1, long long xmin, long long ymin, long long xmax, long long ymax);
drawvec clip_lines(drawvec &geom, int z, long long buffer);
drawvec stairstep(drawvec &geom, int z, int detail);
Expand All @@ -97,6 +97,7 @@ drawvec clip_point(drawvec &geom, long long x1, long long y1, long long x2, long
void visvalingam(drawvec &ls, size_t start, size_t end, double threshold, size_t retain);
int pnpoly(const drawvec &vert, size_t start, size_t nvert, long long testx, long long testy);
double distance_from_line(long long point_x, long long point_y, long long segA_x, long long segA_y, long long segB_x, long long segB_y);
bool can_be_dust(drawvec const &geom, size_t i, size_t j, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos);

std::string overzoom(mvt_tile tile, int oz, int ox, int oy, int nz, int nx, int ny,
int detail, int buffer, std::set<std::string> const &keep, bool do_compress);
Expand Down
12 changes: 9 additions & 3 deletions tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,9 +609,12 @@ void *partial_feature_worker(void *v) {

signed char t = (*partials)[i].t;
int z = (*partials)[i].z;
int tx = (*partials)[i].tx;
int ty = (*partials)[i].ty;
int out_detail = (*partials)[i].extra_detail;

drawvec geom = (*partials)[i].geoms[0];
drawvec before_scaling = (*partials)[i].geoms[0];
to_tile_scale(geom, z, out_detail);

if (t == VT_POLYGON) {
Expand All @@ -625,8 +628,11 @@ void *partial_feature_worker(void *v) {
check_polygon(geom);
}

if (geom.size() < 3) {
if (area > 0) {
if (geom.size() < 4) {
// Don't try to revive a continuous polygon, because we should be
// able to rely on its three fixed points to keep it alive if it
// actually has any area at this zoom level.
if (area > 0 && can_be_dust(before_scaling, 0, before_scaling.size(), z, tx, ty, a->shared_nodes_map, a->nodepos)) {
// area is in world coordinates, calculated before scaling down
geom = revive_polygon(before, area, z, out_detail);
} else {
Expand Down Expand Up @@ -2207,7 +2213,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
bool prevent_tiny = prevent[P_TINY_POLYGON_REDUCTION] ||
(prevent[P_TINY_POLYGON_REDUCTION_AT_MAXZOOM] && z == maxzoom);
if (!prevent_tiny && !additional[A_GRID_LOW_ZOOMS]) {
sf.geometry = reduce_tiny_poly(sf.geometry, z, line_detail, &still_need_simplification_after_reduction, &simplified_away_by_reduction, &accum_area, &sf, &tiny_feature);
sf.geometry = reduce_tiny_poly(sf.geometry, z, tx, ty, line_detail, &still_need_simplification_after_reduction, &simplified_away_by_reduction, &accum_area, &sf, &tiny_feature, shared_nodes_map, nodepos);
if (simplified_away_by_reduction) {
strategy->tiny_polygons++;
}
Expand Down

0 comments on commit 67cb8c5

Please sign in to comment.