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

Don't allow continuous polygons to collapse into dust #155

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
67 changes: 50 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,6 +509,26 @@ drawvec impose_tile_boundaries(drawvec &geom, long long extent) {
return out;
}

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) {
d.x += tx * (1LL << (32 - z));
d.y += ty * (1LL << (32 - z));
}

// to quadkey
struct node n;
n.index = encode_quadkey((unsigned) d.x, (unsigned) d.y);

if (bsearch(&n, shared_nodes_map, nodepos / sizeof(node), sizeof(node), nodecmp) != NULL) {
return true;
}
}

return false;
}

drawvec simplify_lines(drawvec &geom, int z, int tx, int ty, int detail, bool mark_tile_bounds, double simplification, size_t retain, drawvec const &shared_nodes, struct node *shared_nodes_map, size_t nodepos) {
int res = 1 << (32 - detail - z);
long long area = 1LL << (32 - z);
Expand All @@ -509,26 +553,15 @@ drawvec simplify_lines(drawvec &geom, int z, int tx, int ty, int detail, bool ma
// 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;
}

if (nodepos > 0) {
// offset to global
draw d = geom[i];
if (z != 0) {
d.x += tx * (1LL << (32 - z));
d.y += ty * (1LL << (32 - z));
}

// to quadkey
struct node n;
n.index = encode_quadkey((unsigned) d.x, (unsigned) d.y);

if (bsearch(&n, shared_nodes_map, nodepos / sizeof(node), sizeof(node), nodecmp) != NULL) {
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
Loading