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

Replace Wagyu with a new polygon cleaner #164

Draft
wants to merge 51 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
e15239e
Starting on my own polygon cleaner
e-n-f Nov 8, 2023
966b911
Setting up for scanline
e-n-f Nov 8, 2023
6bebc1b
Doing the scan line through the segments
e-n-f Nov 8, 2023
31defc1
Line intersection algorithms
e-n-f Nov 9, 2023
c540ec5
More progress on intersecting
e-n-f Nov 9, 2023
690738b
Add some missing headers
e-n-f Nov 9, 2023
3f98aa9
More missing headers and compiler warnings
e-n-f Nov 9, 2023
22c308f
Do some intersecting
e-n-f Nov 9, 2023
474270c
Visual testing
e-n-f Nov 9, 2023
5ba24f0
Get rid of most spikes
e-n-f Nov 9, 2023
6bd0cdc
Fix multiply duplicated spikes
e-n-f Nov 9, 2023
35231d3
Deal with vertical lines
e-n-f Nov 9, 2023
f6305b9
Deal with horizontals
e-n-f Nov 10, 2023
5e14b68
Ring search basically works now?
e-n-f Nov 10, 2023
c592027
Remove debug spew
e-n-f Nov 10, 2023
e849d42
Bow spindle polygons out in the center to prevent collapse
e-n-f Nov 10, 2023
10290b1
Committing to integer coordinates to fix more accidental mirror segs
e-n-f Nov 10, 2023
5d6a54a
Ring nesting isn't right yet, so just keep the outer rings
e-n-f Nov 12, 2023
3eddb81
Trying to straighten out ring nesting
e-n-f Nov 13, 2023
ba9dbda
Something is wrong with the traversal
e-n-f Nov 13, 2023
c0866b9
Maybe right now?
e-n-f Nov 13, 2023
d06363e
Turn polygon revival back on; turn off some debug spew
e-n-f Nov 13, 2023
bd24168
Add missing header
e-n-f Nov 13, 2023
546b5fd
Remove collinear points
e-n-f Nov 13, 2023
e80d878
Drop holes that are not inside an outer ring
e-n-f Nov 13, 2023
d23f0a2
Speed improvements from doing less repetitive rounding
e-n-f Nov 13, 2023
1238711
Only reinspect segments that changed in the previous pass
e-n-f Nov 13, 2023
c05ae1b
Compare segments to the current pool as they come into scope
e-n-f Nov 13, 2023
dd8762d
Remove dead code
e-n-f Nov 14, 2023
bee87bd
Limit decay into polygon dust to reasonably compact polygons
e-n-f Nov 14, 2023
624c2b6
Try to fix winding reversals introduced by scaling
e-n-f Nov 14, 2023
b22d6c8
Remove debug spew
e-n-f Nov 14, 2023
78a9647
Don't revive spikes that are beyond the tile edge
e-n-f Nov 14, 2023
52e6e74
So many affected tests
e-n-f Nov 14, 2023
68d7d90
Clean up
e-n-f Nov 14, 2023
8a996b9
Tiebreaker for comparing rings of the same area
e-n-f Nov 14, 2023
9e46ac8
Tiebreaker for snap-rounding examination order
e-n-f Nov 14, 2023
33052aa
Make polygon scaling its own function
e-n-f Nov 15, 2023
ef271ad
Switch other calls to Wagyu over. But now coalesce is slow.
e-n-f Nov 15, 2023
21f0204
Make polygon cleaning output idempotent
e-n-f Nov 16, 2023
0cb09db
Merge remote-tracking branch 'origin/main' into clean-polygons
e-n-f Dec 22, 2023
bfb0104
Sketch of finding intersections by bubbling
e-n-f Dec 22, 2023
8d9f1e6
Add special case for collinear verticals
e-n-f Dec 22, 2023
262ab8e
Actually, handle collinear verticals and diagonals together here
e-n-f Dec 22, 2023
7130d21
Merge remote-tracking branch 'origin/main' into clean-polygons
e-n-f Dec 22, 2023
e58892c
Replace a pair with a named structure
e-n-f Dec 22, 2023
e88bdde
Trying to remember where I left off
e-n-f Feb 22, 2024
9b2c5ba
Merge remote-tracking branch 'origin/main' into clean-polygons
e-n-f Feb 22, 2024
9279c8e
Debugging
e-n-f Feb 23, 2024
aeba5d6
Intersecting only at endpoints is fine and doesn't require any work
e-n-f Feb 23, 2024
c594382
Trying to make clipped lines be the correct half
e-n-f Feb 23, 2024
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
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ C = $(wildcard *.c) $(wildcard *.cpp)
INCLUDES = -I/usr/local/include -I.
LIBS = -L/usr/local/lib

tippecanoe: geojson.o jsonpull/jsonpull.o tile.o pool.o mbtiles.o geometry.o projection.o memfile.o mvt.o serial.o main.o text.o dirtiles.o pmtiles_file.o plugin.o read_json.o write_json.o geobuf.o flatgeobuf.o evaluator.o geocsv.o csv.o geojson-loop.o json_logger.o visvalingam.o compression.o clip.o sort.o attribute.o thread.o shared_borders.o
tippecanoe: geojson.o jsonpull/jsonpull.o tile.o pool.o mbtiles.o geometry.o projection.o memfile.o mvt.o serial.o main.o text.o dirtiles.o pmtiles_file.o plugin.o read_json.o write_json.o geobuf.o flatgeobuf.o evaluator.o geocsv.o csv.o geojson-loop.o json_logger.o visvalingam.o compression.o clip.o sort.o attribute.o thread.o shared_borders.o polygon.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread

tippecanoe-enumerate: enumerate.o
Expand All @@ -67,7 +67,7 @@ tippecanoe-enumerate: enumerate.o
tippecanoe-decode: decode.o projection.o mvt.o write_json.o text.o jsonpull/jsonpull.o dirtiles.o pmtiles_file.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3

tile-join: tile-join.o projection.o mbtiles.o mvt.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o evaluator.o csv.o write_json.o pmtiles_file.o clip.o attribute.o thread.o
tile-join: tile-join.o projection.o mbtiles.o mvt.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o evaluator.o csv.o write_json.o pmtiles_file.o clip.o attribute.o thread.o polygon.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread

tippecanoe-json-tool: jsontool.o jsonpull/jsonpull.o csv.o text.o geojson-loop.o
Expand All @@ -76,7 +76,7 @@ tippecanoe-json-tool: jsontool.o jsonpull/jsonpull.o csv.o text.o geojson-loop.o
unit: unit.o text.o sort.o mvt.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread

tippecanoe-overzoom: overzoom.o mvt.o clip.o evaluator.o jsonpull/jsonpull.o text.o attribute.o
tippecanoe-overzoom: overzoom.o mvt.o clip.o evaluator.o jsonpull/jsonpull.o text.o attribute.o polygon.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread

-include $(wildcard *.d)
Expand Down
32 changes: 30 additions & 2 deletions clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "errors.hpp"
#include "compression.hpp"
#include "mvt.hpp"
#include "polygon.hpp"
#include "evaluator.hpp"
#include "serial.hpp"
#include "attribute.hpp"
Expand Down Expand Up @@ -340,7 +341,7 @@ drawvec clean_or_clip_poly(drawvec &geom, int z, int buffer, bool clip, bool try
if (k != i) {
fprintf(f, ",");
}
fprintf(f, "[%lld,%lld]", geom[k].x, geom[k].y);
fprintf(f, "[%lld,%lld]", (long long) geom[k].x, (long long) geom[k].y);
}

fprintf(f, "]");
Expand Down Expand Up @@ -993,7 +994,11 @@ std::string overzoom(const mvt_tile &tile, int oz, int ox, int oy, int nz, int n

// Scale to output tile extent

to_tile_scale(geom, nz, det);
if (t == VT_POLYGON) {
geom = scale_polygon(geom, nz, det);
} else {
to_tile_scale(geom, nz, det);
}

if (!sametile) {
// Clean geometries
Expand All @@ -1005,6 +1010,7 @@ std::string overzoom(const mvt_tile &tile, int oz, int ox, int oy, int nz, int n
}

if (t == VT_POLYGON) {
geom = clean_polygon(geom, 1LL << det);
geom = close_poly(geom);
}

Expand Down Expand Up @@ -1072,3 +1078,25 @@ std::string overzoom(const mvt_tile &tile, int oz, int ox, int oy, int nz, int n
return "";
}
}

/* pnpoly:
Copyright (c) 1970-2003, Wm. Randolph Franklin

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
Redistributions in binary form must reproduce the above copyright notice in the documentation and/or other materials provided with the distribution.
The name of W. Randolph Franklin may not be used to endorse or promote products derived from this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

int pnpoly(const drawvec &vert, size_t start, size_t nvert, long long testx, long long testy) {
size_t i, j;
bool c = false;
for (i = 0, j = nvert - 1; i < nvert; j = i++) {
if (((vert[i + start].y > testy) != (vert[j + start].y > testy)) &&
(testx < (vert[j + start].x - vert[i + start].x) * (testy - vert[i + start].y) / (double) (vert[j + start].y - vert[i + start].y) + vert[i + start].x))
c = !c;
}
return c;
}
48 changes: 25 additions & 23 deletions geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,6 @@ drawvec decode_geometry(const char **meta, int z, unsigned tx, unsigned ty, long
return out;
}

/* pnpoly:
Copyright (c) 1970-2003, Wm. Randolph Franklin

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
Redistributions in binary form must reproduce the above copyright notice in the documentation and/or other materials provided with the distribution.
The name of W. Randolph Franklin may not be used to endorse or promote products derived from this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

int pnpoly(const drawvec &vert, size_t start, size_t nvert, long long testx, long long testy) {
size_t i, j;
bool c = false;
for (i = 0, j = nvert - 1; i < nvert; j = i++) {
if (((vert[i + start].y > testy) != (vert[j + start].y > testy)) &&
(testx < (vert[j + start].x - vert[i + start].x) * (testy - vert[i + start].y) / (double) (vert[j + start].y - vert[i + start].y) + vert[i + start].x))
c = !c;
}
return c;
}

void check_polygon(drawvec &geom) {
geom = remove_noop(geom, VT_POLYGON, 0);

Expand Down Expand Up @@ -168,6 +146,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 const &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;
Expand All @@ -188,6 +178,17 @@ drawvec reduce_tiny_poly(drawvec const &geom, int z, int detail, bool *still_nee
}

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
Expand All @@ -205,7 +206,8 @@ drawvec reduce_tiny_poly(drawvec const &geom, int z, int detail, bool *still_nee
// 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;

Expand Down
17 changes: 12 additions & 5 deletions plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "geometry.hpp"
#include "serial.hpp"
#include "errors.hpp"
#include "polygon.hpp"
#include "thread.hpp"

extern "C" {
Expand Down Expand Up @@ -196,16 +197,22 @@ std::vector<mvt_layer> parse_layers(int fd, int z, unsigned x, unsigned y, std::
dv = fix_polygon(dv);
}

// Scale and offset geometry from global to tile
// Offset geometry from global to tile
for (size_t i = 0; i < dv.size(); i++) {
long long scale = 1LL << (32 - z);
dv[i].x = std::round((dv[i].x - scale * x) * extent / (double) scale);
dv[i].y = std::round((dv[i].y - scale * y) * extent / (double) scale);
dv[i].x = dv[i].x - scale * x;
dv[i].y = dv[i].y - scale * y;
}
// Scale to tile extent
int detail = std::round(log(extent) / log(2));
if (t == VT_POLYGON) {
dv = scale_polygon(dv, z, detail);
} else {
to_tile_scale(dv, z, detail);
}

if (mb_geometry[t] == VT_POLYGON) {
// we can try scaling up because these are tile coordinates
dv = clean_or_clip_poly(dv, 0, 0, false, true);
dv = clean_polygon(dv, extent); // tile coordinates
if (dv.size() < 3) {
dv.clear();
}
Expand Down
Loading
Loading