mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
With --no-simplification-of-shared-nodes, simplify_lines() used to offset every vertex of every feature to world coordinates and check it against the Bloom filter and the global sorted list of shared nodes, in every tile at every zoom level. Whether a vertex is a shared node depends only on its world coordinates, so now it is found once, after the list of shared nodes has been made and before the geometry is sorted, by a parallel pass over each reader's geometry that marks each vertex in place, in the upper bits of its serialized operation byte. Decoding puts that state into a new field of draw (which still fits in 16 bytes), and it is carried through clipping, the copies across the antimeridian at z0, and the geometry written for the next zoom level. Polygon cleaning of coalesced features restores the state of any output vertex with the same coordinates as an input vertex. Vertices whose state is still unknown, because they were created by clipping or polygon cleaning or came back from a prefilter, are still looked up in the global list when they are simplified, so the output is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2nBqZisxNQfmEmon3vE9v
211 lines
7.8 KiB
C++
211 lines
7.8 KiB
C++
#ifndef GEOMETRY_HPP
|
|
#define GEOMETRY_HPP
|
|
|
|
#include <vector>
|
|
#include <atomic>
|
|
#include <set>
|
|
#include <string>
|
|
#include <sqlite3.h>
|
|
#include <stdio.h>
|
|
#include <mvt.hpp>
|
|
#include "jsonpull/jsonpull.h"
|
|
#include "attribute.hpp"
|
|
|
|
#define VT_POINT 1
|
|
#define VT_LINE 2
|
|
#define VT_POLYGON 3
|
|
|
|
#define VT_END 0
|
|
#define VT_MOVETO 1
|
|
#define VT_LINETO 2
|
|
#define VT_CLOSEPATH 7
|
|
|
|
// Whether a vertex is one of the shared nodes that --no-simplification-of-shared-nodes
|
|
// must not simplify away. This is a function only of the vertex's world coordinates,
|
|
// so it is found once, before tiling, from the global list of shared nodes, and then
|
|
// carried along with the vertex, instead of being looked up again for each tile.
|
|
// Vertices that are created during tiling, by clipping or polygon cleaning,
|
|
// start out NODE_UNKNOWN and are looked up in the global list if they are simplified.
|
|
#define NODE_UNKNOWN 0
|
|
#define NODE_NOT_SHARED 1
|
|
#define NODE_SHARED 2
|
|
|
|
// In serialized geometry, the node state is stored in the upper bits
|
|
// of the byte that holds each vertex's operation.
|
|
#define NODE_SHIFT 4
|
|
#define NODE_MASK 3
|
|
#define OP_MASK 0x0F
|
|
|
|
// The bitfield is to make sizeof(draw) be 16 instead of 24
|
|
// at the cost, apparently, of a 0.7% increase in running time
|
|
// for packing and unpacking.
|
|
struct draw {
|
|
long long x : 40;
|
|
signed char op;
|
|
long long y : 40;
|
|
signed char necessary;
|
|
signed char node;
|
|
|
|
draw(int nop, long long nx, long long ny)
|
|
: x(nx),
|
|
op(nop),
|
|
y(ny),
|
|
necessary(0),
|
|
node(NODE_UNKNOWN) {
|
|
}
|
|
|
|
draw(int nop, long long nx, long long ny, signed char nnode)
|
|
: x(nx),
|
|
op(nop),
|
|
y(ny),
|
|
necessary(0),
|
|
node(nnode) {
|
|
}
|
|
|
|
draw()
|
|
: x(0),
|
|
op(0),
|
|
y(0),
|
|
necessary(0),
|
|
node(NODE_UNKNOWN) {
|
|
}
|
|
|
|
bool operator<(draw const &s) const {
|
|
if (y < s.y || (y == s.y && x < s.x)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool operator>(draw const &s) const {
|
|
return s < *this;
|
|
}
|
|
|
|
bool operator==(draw const &s) const {
|
|
return y == s.y && x == s.x;
|
|
}
|
|
|
|
bool operator!=(draw const &s) const {
|
|
return y != s.y || x != s.x;
|
|
}
|
|
};
|
|
|
|
static_assert(sizeof(draw) == 16, "draw should still fit in 16 bytes");
|
|
|
|
typedef std::vector<draw> drawvec;
|
|
struct serial_feature;
|
|
|
|
drawvec decode_geometry(const char **meta, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y);
|
|
void to_tile_scale(drawvec &geom, int z, int detail);
|
|
drawvec from_tile_scale(drawvec const &geom, int z, int detail);
|
|
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(const drawvec &geom, int z, int detail, bool *still_needs_simplification, bool *reduced_away, double *accum_area, double tiny_polygon_size);
|
|
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);
|
|
bool point_within_tile(long long x, long long y, int z);
|
|
int quick_check(const long long *bbox, int z, long long buffer);
|
|
void douglas_peucker(drawvec &geom, int start, int n, double e, size_t kept, size_t retain, bool prevent_simplify_shared_nodes);
|
|
bool is_shared_node(long long wx, long long wy, struct node const *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom);
|
|
void restore_node_states(drawvec const &from, drawvec &to);
|
|
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, std::string const &shared_nodes_bloom);
|
|
drawvec reorder_lines(const drawvec &geom);
|
|
drawvec fix_polygon(const drawvec &geom, bool use_winding, bool reverse_winding);
|
|
std::vector<drawvec> chop_polygon(std::vector<drawvec> &geoms);
|
|
void check_polygon(drawvec &geom);
|
|
double get_area(const drawvec &geom, size_t i, size_t j);
|
|
double get_mp_area(drawvec &geom);
|
|
drawvec polygon_to_anchor(const drawvec &geom);
|
|
drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigned long long label_point);
|
|
|
|
drawvec simple_clip_poly(drawvec &geom, int z, int buffer, drawvec &shared_nodes, bool prevent_simplify_shared_nodes);
|
|
drawvec simple_clip_poly(drawvec &geom, long long x1, long long y1, long long x2, long long y2, bool prevent_simplify_shared_nodes);
|
|
drawvec simple_clip_poly(drawvec &geom, long long x1, long long y1, long long x2, long long y2,
|
|
long long ax, long long ay, long long bx, long long by, drawvec &shared_nodes, bool prevent_simplify_shared_nodes);
|
|
drawvec clip_lines(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
|
|
drawvec clip_point(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
|
|
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);
|
|
bool pnpoly_mp(drawvec const &geom, long long x, long long y);
|
|
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);
|
|
|
|
drawvec clip_poly_poly(drawvec const &geom, drawvec const &bounds);
|
|
drawvec clip_lines_poly(drawvec const &geom, drawvec const &bounds);
|
|
drawvec clip_point_poly(drawvec const &geom, drawvec const &bounds);
|
|
|
|
struct input_tile {
|
|
std::string tile;
|
|
int z;
|
|
int x;
|
|
int y;
|
|
};
|
|
|
|
struct source_tile {
|
|
mvt_tile tile;
|
|
int z;
|
|
int x;
|
|
int y;
|
|
};
|
|
|
|
struct clipbbox {
|
|
double lon1;
|
|
double lat1;
|
|
double lon2;
|
|
double lat2;
|
|
|
|
long long minx;
|
|
long long miny;
|
|
long long maxx;
|
|
long long maxy;
|
|
|
|
drawvec dv; // empty, or arbitrary clipping polygon
|
|
};
|
|
|
|
std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int ny,
|
|
int detail, int buffer,
|
|
std::set<std::string> const &keep,
|
|
std::set<std::string> const &exclude,
|
|
std::vector<std::string> const &exclude_prefix,
|
|
bool do_compress,
|
|
std::vector<std::pair<unsigned, unsigned>> *next_overzoomed_tiles,
|
|
bool demultiply, json_object *filter, bool preserve_input_order,
|
|
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
|
std::vector<std::string> const &unidecode_data, double simplification,
|
|
double tiny_polygon_size,
|
|
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
|
std::string const &accumulate_numeric, size_t feature_limit,
|
|
std::vector<clipbbox> const &clipbboxes,
|
|
bool deduplicate_by_id);
|
|
|
|
std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int ny,
|
|
int detail, int buffer,
|
|
std::set<std::string> const &keep,
|
|
std::set<std::string> const &exclude,
|
|
std::vector<std::string> const &exclude_prefix,
|
|
bool do_compress,
|
|
std::vector<std::pair<unsigned, unsigned>> *next_overzoomed_tiles,
|
|
bool demultiply, json_object *filter, bool preserve_input_order,
|
|
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
|
std::vector<std::string> const &unidecode_data, double simplification,
|
|
double tiny_polygon_size,
|
|
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
|
std::string const &accumulate_numeric, size_t feature_limit,
|
|
std::vector<clipbbox> const &clipbboxes,
|
|
bool deduplicate_by_id);
|
|
|
|
draw center_of_mass_mp(const drawvec &dv);
|
|
|
|
void get_quadkey_bounds(long long xmin, long long ymin, long long xmax, long long ymax,
|
|
unsigned long long *start, unsigned long long *end);
|
|
|
|
clipbbox parse_clip_poly(std::string arg);
|
|
|
|
bool line_is_too_small(drawvec const &geometry, int z, int detail);
|
|
void coalesce_polygon(drawvec &geom, bool scale_up);
|
|
|
|
#endif
|