Make struct partial a serial_feature wrapper rather than its own thing

This commit is contained in:
Erica Fischer
2023-02-08 15:49:42 -08:00
parent de607d1440
commit 4cd40c72ea
+303 -349
View File
@@ -460,53 +460,28 @@ struct accum_state {
}; };
struct partial { struct partial {
std::vector<drawvec> geoms = std::vector<drawvec>(); serial_feature sf;
std::vector<long long> keys = std::vector<long long>();
std::vector<long long> values = std::vector<long long>(); bool coalesced = 0; // coalesced-as-needed
std::vector<std::string> full_keys = std::vector<std::string>(); ssize_t renamed = 0; // renumbered in border-matching
std::vector<serial_val> full_values = std::vector<serial_val>(); long long clustered = 0;
std::vector<ssize_t> arc_polygon = std::vector<ssize_t>();
long long layer = 0;
long long original_seq = 0;
unsigned long long index = 0;
unsigned long long label_point = 0;
int segment = 0;
bool reduced = 0;
bool coalesced = 0;
int z = 0; int z = 0;
int tx = 0; int tx = 0;
int ty = 0; int ty = 0;
int line_detail = 0; int line_detail = 0;
int extra_detail = 0; int extra_detail = 0;
int maxzoom = 0; int maxzoom = 0;
double spacing = 0;
double simplification = 0; double simplification = 0;
signed char t = 0;
unsigned long long id = 0; bool reduced = false; // polygon dust / tiny polygon
bool has_id = 0; std::vector<ssize_t> arc_polygon;
ssize_t renamed = 0;
long long extent = 0;
long long clustered = 0;
std::set<std::string> need_tilestats; std::set<std::string> need_tilestats;
std::map<std::string, accum_state> attribute_accum_state; std::map<std::string, accum_state> attribute_accum_state;
double spacing = 0; // for the glow attribute
partial(serial_feature &sf, int z_, int tx_, int ty_, int line_detail_, int maxzoom_, double simplification_) { partial(serial_feature &sf_, int z_, int tx_, int ty_, int line_detail_, int maxzoom_, double simplification_) {
geoms.clear(); sf = sf_;
geoms.push_back(sf.geometry);
layer = sf.layer;
t = sf.t;
segment = sf.segment;
original_seq = sf.seq;
keys = sf.keys;
values = sf.values;
full_keys = sf.full_keys;
full_values = sf.full_values;
id = sf.id;
has_id = sf.has_id;
index = sf.index;
label_point = sf.label_point;
extent = sf.extent;
z = z_; z = z_;
tx = tx_; tx = tx_;
@@ -580,7 +555,7 @@ static mvt_value find_attribute_value(const partial *c1, std::string key, const
if (key == ORDER_BY_SIZE) { if (key == ORDER_BY_SIZE) {
mvt_value v; mvt_value v;
v.type = mvt_double; v.type = mvt_double;
v.numeric_value.double_value = c1->extent; v.numeric_value.double_value = c1->sf.extent;
return v; return v;
} }
if (key == ORDER_BY_INTERESTINGNESS) { if (key == ORDER_BY_INTERESTINGNESS) {
@@ -590,9 +565,9 @@ static mvt_value find_attribute_value(const partial *c1, std::string key, const
return v; return v;
} }
const std::vector<long long> &keys1 = c1->keys; const std::vector<long long> &keys1 = c1->sf.keys;
const std::vector<long long> &values1 = c1->values; const std::vector<long long> &values1 = c1->sf.values;
const char *stringpool1 = stringpool + pool_off[c1->segment]; const char *stringpool1 = stringpool + pool_off[c1->sf.segment];
for (size_t i = 0; i < keys1.size(); i++) { for (size_t i = 0; i < keys1.size(); i++) {
mvt_value key1 = retrieve_string(keys1[i], stringpool1, NULL); mvt_value key1 = retrieve_string(keys1[i], stringpool1, NULL);
@@ -601,9 +576,9 @@ static mvt_value find_attribute_value(const partial *c1, std::string key, const
} }
} }
for (size_t i = 0; i < c1->full_keys.size(); i++) { for (size_t i = 0; i < c1->sf.full_keys.size(); i++) {
if (c1->full_keys[i] == key) { if (c1->sf.full_keys[i] == key) {
return stringified_to_mvt_value(c1->full_values[i].type, c1->full_values[i].s.c_str()); return stringified_to_mvt_value(c1->sf.full_values[i].type, c1->sf.full_values[i].s.c_str());
} }
} }
@@ -634,14 +609,14 @@ static bool order_partials(const char *stringpool, long long pool_off[], const s
} }
if (prevent[P_INPUT_ORDER]) { if (prevent[P_INPUT_ORDER]) {
if (a.seq < b.original_seq) { if (a.seq < b.sf.seq) {
return true; return true;
} else if (a.seq > b.original_seq) { } else if (a.seq > b.sf.seq) {
return false; return false;
} // else they are equal, so continue to the index } // else they are equal, so continue to the index
} }
if (a.index < b.index) { if (a.index < b.sf.index) {
return true; return true;
} }
@@ -690,16 +665,10 @@ drawvec revive_polygon(drawvec &geom, double area, int z, int detail) {
} }
double simplify_partial(partial *p, drawvec &shared_nodes) { double simplify_partial(partial *p, drawvec &shared_nodes) {
drawvec geom; drawvec geom = p->sf.geometry;
for (size_t j = 0; j < p->geoms.size(); j++) { p->sf.geometry.clear(); // avoid keeping two copies in memory
for (size_t k = 0; k < p->geoms[j].size(); k++) { signed char t = p->sf.t;
geom.push_back(p->geoms[j][k]);
}
}
p->geoms.clear(); // avoid keeping two copies in memory
signed char t = p->t;
int z = p->z; int z = p->z;
int line_detail = p->line_detail; int line_detail = p->line_detail;
int maxzoom = p->maxzoom; int maxzoom = p->maxzoom;
@@ -751,7 +720,7 @@ double simplify_partial(partial *p, drawvec &shared_nodes) {
geom = reorder_lines(geom); geom = reorder_lines(geom);
} }
p->geoms.push_back(geom); p->sf.geometry = geom;
return area; return area;
} }
@@ -762,11 +731,11 @@ void *partial_feature_worker(void *v) {
for (size_t i = a->task; i < (*partials).size(); i += a->tasks) { for (size_t i = a->task; i < (*partials).size(); i += a->tasks) {
double area = simplify_partial(&((*partials)[i]), *(a->shared_nodes)); double area = simplify_partial(&((*partials)[i]), *(a->shared_nodes));
signed char t = (*partials)[i].t; signed char t = (*partials)[i].sf.t;
int z = (*partials)[i].z; int z = (*partials)[i].z;
int out_detail = (*partials)[i].extra_detail; int out_detail = (*partials)[i].extra_detail;
drawvec geom = (*partials)[i].geoms[0]; drawvec geom = (*partials)[i].sf.geometry;
to_tile_scale(geom, z, out_detail); to_tile_scale(geom, z, out_detail);
if (t == VT_POLYGON) { if (t == VT_POLYGON) {
@@ -791,16 +760,13 @@ void *partial_feature_worker(void *v) {
} }
if (t == VT_POLYGON && additional[A_GENERATE_POLYGON_LABEL_POINTS]) { if (t == VT_POLYGON && additional[A_GENERATE_POLYGON_LABEL_POINTS]) {
t = (*partials)[i].t = VT_POINT; t = (*partials)[i].sf.t = VT_POINT;
geom = checkerboard_anchors(from_tile_scale(geom, z, out_detail), (*partials)[i].tx, (*partials)[i].ty, z, (*partials)[i].label_point); geom = checkerboard_anchors(from_tile_scale(geom, z, out_detail), (*partials)[i].tx, (*partials)[i].ty, z, (*partials)[i].sf.label_point);
to_tile_scale(geom, z, out_detail); to_tile_scale(geom, z, out_detail);
} }
(*partials)[i].index = i; (*partials)[i].sf.index = i;
(*partials)[i].sf.geometry = geom;
std::vector<drawvec> geoms; // artifact of former polygon-splitting to reduce geometric complexity
geoms.push_back(geom);
(*partials)[i].geoms = geoms;
} }
return NULL; return NULL;
@@ -919,21 +885,19 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
size_t merge_count = ceil((1 - merge_fraction) * partials.size()); size_t merge_count = ceil((1 - merge_fraction) * partials.size());
for (size_t i = 0; i < partials.size(); i++) { for (size_t i = 0; i < partials.size(); i++) {
if (partials[i].t == VT_POLYGON) { if (partials[i].sf.t == VT_POLYGON) {
for (size_t j = 0; j < partials[i].geoms.size(); j++) { drawvec &g = partials[i].sf.geometry;
drawvec &g = partials[i].geoms[j]; drawvec out;
drawvec out;
for (size_t k = 0; k < g.size(); k++) { for (size_t k = 0; k < g.size(); k++) {
if (g[k].op == VT_LINETO && k > 0 && g[k - 1] == g[k]) { if (g[k].op == VT_LINETO && k > 0 && g[k - 1] == g[k]) {
; ;
} else { } else {
out.push_back(g[k]); out.push_back(g[k]);
}
} }
partials[i].geoms[j] = out;
} }
partials[i].sf.geometry = out;
} }
} }
@@ -944,25 +908,23 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
std::vector<edge> edges; std::vector<edge> edges;
size_t ring = 0; size_t ring = 0;
for (size_t i = 0; i < partials.size(); i++) { for (size_t i = 0; i < partials.size(); i++) {
if (partials[i].t == VT_POLYGON) { if (partials[i].sf.t == VT_POLYGON) {
for (size_t j = 0; j < partials[i].geoms.size(); j++) { for (size_t k = 0; k + 1 < partials[i].sf.geometry.size(); k++) {
for (size_t k = 0; k + 1 < partials[i].geoms[j].size(); k++) { if (partials[i].sf.geometry[k].op == VT_MOVETO) {
if (partials[i].geoms[j][k].op == VT_MOVETO) { ring++;
ring++; }
if (partials[i].sf.geometry[k + 1].op == VT_LINETO) {
drawvec dv;
if (partials[i].sf.geometry[k] < partials[i].sf.geometry[k + 1]) {
dv.push_back(partials[i].sf.geometry[k]);
dv.push_back(partials[i].sf.geometry[k + 1]);
} else {
dv.push_back(partials[i].sf.geometry[k + 1]);
dv.push_back(partials[i].sf.geometry[k]);
} }
if (partials[i].geoms[j][k + 1].op == VT_LINETO) { edges.push_back(edge(dv[0].x, dv[0].y, dv[1].x, dv[1].y, ring));
drawvec dv;
if (partials[i].geoms[j][k] < partials[i].geoms[j][k + 1]) {
dv.push_back(partials[i].geoms[j][k]);
dv.push_back(partials[i].geoms[j][k + 1]);
} else {
dv.push_back(partials[i].geoms[j][k + 1]);
dv.push_back(partials[i].geoms[j][k]);
}
edges.push_back(edge(dv[0].x, dv[0].y, dv[1].x, dv[1].y, ring));
}
} }
} }
} }
@@ -975,74 +937,72 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
// is not the same as the set of rings using the edge on the other side. // is not the same as the set of rings using the edge on the other side.
for (size_t i = 0; i < partials.size(); i++) { for (size_t i = 0; i < partials.size(); i++) {
if (partials[i].t == VT_POLYGON) { if (partials[i].sf.t == VT_POLYGON) {
for (size_t j = 0; j < partials[i].geoms.size(); j++) { drawvec &g = partials[i].sf.geometry;
drawvec &g = partials[i].geoms[j];
for (size_t k = 0; k < g.size(); k++) { for (size_t k = 0; k < g.size(); k++) {
g[k].necessary = 0; g[k].necessary = 0;
} }
for (size_t a = 0; a < g.size(); a++) { for (size_t a = 0; a < g.size(); a++) {
if (g[a].op == VT_MOVETO) { if (g[a].op == VT_MOVETO) {
size_t b; size_t b;
for (b = a + 1; b < g.size(); b++) { for (b = a + 1; b < g.size(); b++) {
if (g[b].op != VT_LINETO) { if (g[b].op != VT_LINETO) {
break; break;
}
} }
}
// -1 because of duplication at the end // -1 because of duplication at the end
size_t s = b - a - 1; size_t s = b - a - 1;
if (s > 0) { if (s > 0) {
drawvec left; drawvec left;
if (g[a + (s - 1) % s] < g[a]) { if (g[a + (s - 1) % s] < g[a]) {
left.push_back(g[a + (s - 1) % s]); left.push_back(g[a + (s - 1) % s]);
left.push_back(g[a]); left.push_back(g[a]);
} else {
left.push_back(g[a]);
left.push_back(g[a + (s - 1) % s]);
}
if (left[1] < left[0]) {
fprintf(stderr, "left misordered\n");
}
std::pair<std::vector<edge>::iterator, std::vector<edge>::iterator> e1 = std::equal_range(edges.begin(), edges.end(), edge(left[0].x, left[0].y, left[1].x, left[1].y, 0));
for (size_t k = 0; k < s; k++) {
drawvec right;
if (g[a + k] < g[a + k + 1]) {
right.push_back(g[a + k]);
right.push_back(g[a + k + 1]);
} else { } else {
left.push_back(g[a]); right.push_back(g[a + k + 1]);
left.push_back(g[a + (s - 1) % s]); right.push_back(g[a + k]);
} }
if (left[1] < left[0]) {
std::pair<std::vector<edge>::iterator, std::vector<edge>::iterator> e2 = std::equal_range(edges.begin(), edges.end(), edge(right[0].x, right[0].y, right[1].x, right[1].y, 0));
if (right[1] < right[0]) {
fprintf(stderr, "left misordered\n"); fprintf(stderr, "left misordered\n");
} }
std::pair<std::vector<edge>::iterator, std::vector<edge>::iterator> e1 = std::equal_range(edges.begin(), edges.end(), edge(left[0].x, left[0].y, left[1].x, left[1].y, 0));
for (size_t k = 0; k < s; k++) { if (e1.first == e1.second || e2.first == e2.second) {
drawvec right; fprintf(stderr, "Internal error: polygon edge lookup failed for %lld,%lld to %lld,%lld or %lld,%lld to %lld,%lld\n", left[0].x, left[0].y, left[1].x, left[1].y, right[0].x, right[0].y, right[1].x, right[1].y);
exit(EXIT_IMPOSSIBLE);
if (g[a + k] < g[a + k + 1]) {
right.push_back(g[a + k]);
right.push_back(g[a + k + 1]);
} else {
right.push_back(g[a + k + 1]);
right.push_back(g[a + k]);
}
std::pair<std::vector<edge>::iterator, std::vector<edge>::iterator> e2 = std::equal_range(edges.begin(), edges.end(), edge(right[0].x, right[0].y, right[1].x, right[1].y, 0));
if (right[1] < right[0]) {
fprintf(stderr, "left misordered\n");
}
if (e1.first == e1.second || e2.first == e2.second) {
fprintf(stderr, "Internal error: polygon edge lookup failed for %lld,%lld to %lld,%lld or %lld,%lld to %lld,%lld\n", left[0].x, left[0].y, left[1].x, left[1].y, right[0].x, right[0].y, right[1].x, right[1].y);
exit(EXIT_IMPOSSIBLE);
}
if (!edges_same(e1, e2)) {
g[a + k].necessary = 1;
necessaries.insert(g[a + k]);
}
e1 = e2;
} }
}
a = b - 1; if (!edges_same(e1, e2)) {
g[a + k].necessary = 1;
necessaries.insert(g[a + k]);
}
e1 = e2;
}
} }
a = b - 1;
} }
} }
} }
@@ -1055,116 +1015,114 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
// Roll rings that include a necessary point around so they start at one // Roll rings that include a necessary point around so they start at one
for (size_t i = 0; i < partials.size(); i++) { for (size_t i = 0; i < partials.size(); i++) {
if (partials[i].t == VT_POLYGON) { if (partials[i].sf.t == VT_POLYGON) {
for (size_t j = 0; j < partials[i].geoms.size(); j++) { drawvec &g = partials[i].sf.geometry;
drawvec &g = partials[i].geoms[j];
for (size_t k = 0; k < g.size(); k++) { for (size_t k = 0; k < g.size(); k++) {
if (necessaries.count(g[k]) != 0) { if (necessaries.count(g[k]) != 0) {
g[k].necessary = 1; g[k].necessary = 1;
}
} }
}
for (size_t k = 0; k < g.size(); k++) { for (size_t k = 0; k < g.size(); k++) {
if (g[k].op == VT_MOVETO) { if (g[k].op == VT_MOVETO) {
ssize_t necessary = -1; ssize_t necessary = -1;
ssize_t lowest = k; ssize_t lowest = k;
size_t l; size_t l;
for (l = k + 1; l < g.size(); l++) { for (l = k + 1; l < g.size(); l++) {
if (g[l].op != VT_LINETO) { if (g[l].op != VT_LINETO) {
break;
}
if (g[l].necessary) {
necessary = l;
}
if (g[l] < g[lowest]) {
lowest = l;
}
}
if (necessary < 0) {
necessary = lowest;
// Add a necessary marker if there was none in the ring,
// so the arc code below can find it.
g[lowest].necessary = 1;
}
{
drawvec tmp;
// l - 1 because the endpoint is duplicated
for (size_t m = necessary; m < l - 1; m++) {
tmp.push_back(g[m]);
}
for (ssize_t m = k; m < necessary; m++) {
tmp.push_back(g[m]);
}
// replace the endpoint
tmp.push_back(g[necessary]);
if (tmp.size() != l - k) {
fprintf(stderr, "internal error shifting ring\n");
exit(EXIT_IMPOSSIBLE);
}
for (size_t m = 0; m < tmp.size(); m++) {
if (m == 0) {
tmp[m].op = VT_MOVETO;
} else {
tmp[m].op = VT_LINETO;
}
g[k + m] = tmp[m];
}
}
// Now peel off each set of segments from one necessary point to the next
// into an "arc" as in TopoJSON
for (size_t m = k; m < l; m++) {
if (!g[m].necessary) {
fprintf(stderr, "internal error in arc building\n");
exit(EXIT_IMPOSSIBLE);
}
drawvec arc;
size_t n;
for (n = m; n < l; n++) {
arc.push_back(g[n]);
if (n > m && g[n].necessary) {
break; break;
} }
if (g[l].necessary) {
necessary = l;
}
if (g[l] < g[lowest]) {
lowest = l;
}
} }
if (necessary < 0) { auto f = arcs.find(arc);
necessary = lowest; if (f == arcs.end()) {
// Add a necessary marker if there was none in the ring, drawvec arc2 = reverse_subring(arc);
// so the arc code below can find it.
g[lowest].necessary = 1;
}
{ auto f2 = arcs.find(arc2);
drawvec tmp; if (f2 == arcs.end()) {
// Add new arc
// l - 1 because the endpoint is duplicated size_t added = arcs.size() + 1;
for (size_t m = necessary; m < l - 1; m++) { arcs.insert(std::pair<drawvec, size_t>(arc, added));
tmp.push_back(g[m]); partials[i].arc_polygon.push_back(added);
} merge_candidates.insert(std::pair<ssize_t, size_t>(added, i));
for (ssize_t m = k; m < necessary; m++) {
tmp.push_back(g[m]);
}
// replace the endpoint
tmp.push_back(g[necessary]);
if (tmp.size() != l - k) {
fprintf(stderr, "internal error shifting ring\n");
exit(EXIT_IMPOSSIBLE);
}
for (size_t m = 0; m < tmp.size(); m++) {
if (m == 0) {
tmp[m].op = VT_MOVETO;
} else {
tmp[m].op = VT_LINETO;
}
g[k + m] = tmp[m];
}
}
// Now peel off each set of segments from one necessary point to the next
// into an "arc" as in TopoJSON
for (size_t m = k; m < l; m++) {
if (!g[m].necessary) {
fprintf(stderr, "internal error in arc building\n");
exit(EXIT_IMPOSSIBLE);
}
drawvec arc;
size_t n;
for (n = m; n < l; n++) {
arc.push_back(g[n]);
if (n > m && g[n].necessary) {
break;
}
}
auto f = arcs.find(arc);
if (f == arcs.end()) {
drawvec arc2 = reverse_subring(arc);
auto f2 = arcs.find(arc2);
if (f2 == arcs.end()) {
// Add new arc
size_t added = arcs.size() + 1;
arcs.insert(std::pair<drawvec, size_t>(arc, added));
partials[i].arc_polygon.push_back(added);
merge_candidates.insert(std::pair<ssize_t, size_t>(added, i));
} else {
partials[i].arc_polygon.push_back(-(ssize_t) f2->second);
merge_candidates.insert(std::pair<ssize_t, size_t>(-(ssize_t) f2->second, i));
}
} else { } else {
partials[i].arc_polygon.push_back(f->second); partials[i].arc_polygon.push_back(-(ssize_t) f2->second);
merge_candidates.insert(std::pair<ssize_t, size_t>(f->second, i)); merge_candidates.insert(std::pair<ssize_t, size_t>(-(ssize_t) f2->second, i));
} }
} else {
m = n - 1; partials[i].arc_polygon.push_back(f->second);
merge_candidates.insert(std::pair<ssize_t, size_t>(f->second, i));
} }
partials[i].arc_polygon.push_back(0); m = n - 1;
k = l - 1;
} }
partials[i].arc_polygon.push_back(0);
k = l - 1;
} }
} }
} }
@@ -1218,10 +1176,10 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
if (r1i->second != r2i->second) { if (r1i->second != r2i->second) {
merge_order mo; merge_order mo;
mo.edge = i; mo.edge = i;
if (partials[r1i->second].index > partials[r2i->second].index) { if (partials[r1i->second].sf.index > partials[r2i->second].sf.index) {
mo.gap = partials[r1i->second].index - partials[r2i->second].index; mo.gap = partials[r1i->second].sf.index - partials[r2i->second].sf.index;
} else { } else {
mo.gap = partials[r2i->second].index - partials[r1i->second].index; mo.gap = partials[r2i->second].sf.index - partials[r1i->second].sf.index;
} }
mo.p1 = r1i->second; mo.p1 = r1i->second;
mo.p2 = r2i->second; mo.p2 = r2i->second;
@@ -1361,9 +1319,8 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
// Turn the arc representations of the polygons back into standard polygon geometries // Turn the arc representations of the polygons back into standard polygon geometries
for (size_t i = 0; i < partials.size(); i++) { for (size_t i = 0; i < partials.size(); i++) {
if (partials[i].t == VT_POLYGON) { if (partials[i].sf.t == VT_POLYGON) {
partials[i].geoms.resize(0); partials[i].sf.geometry.clear();
partials[i].geoms.push_back(drawvec());
bool at_start = true; bool at_start = true;
draw first(-1, 0, 0); draw first(-1, 0, 0);
@@ -1372,27 +1329,27 @@ bool find_common_edges(std::vector<partial> &partials, int z, int line_detail, d
if (p == 0) { if (p == 0) {
if (first.op >= 0) { if (first.op >= 0) {
partials[i].geoms[0].push_back(first); partials[i].sf.geometry.push_back(first);
first = draw(-1, 0, 0); first = draw(-1, 0, 0);
} }
at_start = true; at_start = true;
} else if (p > 0) { } else if (p > 0) {
for (size_t k = 0; k + 1 < simplified_arcs[p].size(); k++) { for (size_t k = 0; k + 1 < simplified_arcs[p].size(); k++) {
if (at_start) { if (at_start) {
partials[i].geoms[0].push_back(draw(VT_MOVETO, simplified_arcs[p][k].x, simplified_arcs[p][k].y)); partials[i].sf.geometry.push_back(draw(VT_MOVETO, simplified_arcs[p][k].x, simplified_arcs[p][k].y));
first = draw(VT_LINETO, simplified_arcs[p][k].x, simplified_arcs[p][k].y); first = draw(VT_LINETO, simplified_arcs[p][k].x, simplified_arcs[p][k].y);
} else { } else {
partials[i].geoms[0].push_back(draw(VT_LINETO, simplified_arcs[p][k].x, simplified_arcs[p][k].y)); partials[i].sf.geometry.push_back(draw(VT_LINETO, simplified_arcs[p][k].x, simplified_arcs[p][k].y));
} }
at_start = 0; at_start = 0;
} }
} else { /* p < 0 */ } else { /* p < 0 */
for (ssize_t k = simplified_arcs[-p].size() - 1; k > 0; k--) { for (ssize_t k = simplified_arcs[-p].size() - 1; k > 0; k--) {
if (at_start) { if (at_start) {
partials[i].geoms[0].push_back(draw(VT_MOVETO, simplified_arcs[-p][k].x, simplified_arcs[-p][k].y)); partials[i].sf.geometry.push_back(draw(VT_MOVETO, simplified_arcs[-p][k].x, simplified_arcs[-p][k].y));
first = draw(VT_LINETO, simplified_arcs[-p][k].x, simplified_arcs[-p][k].y); first = draw(VT_LINETO, simplified_arcs[-p][k].x, simplified_arcs[-p][k].y);
} else { } else {
partials[i].geoms[0].push_back(draw(VT_LINETO, simplified_arcs[-p][k].x, simplified_arcs[-p][k].y)); partials[i].sf.geometry.push_back(draw(VT_LINETO, simplified_arcs[-p][k].x, simplified_arcs[-p][k].y));
} }
at_start = 0; at_start = 0;
} }
@@ -1860,51 +1817,51 @@ void preserve_attribute(attribute_op op, serial_feature &, char *stringpool, lon
// If the feature being merged into has this key as a metadata reference, // If the feature being merged into has this key as a metadata reference,
// promote it to a full_key so it can be modified // promote it to a full_key so it can be modified
for (size_t i = 0; i < p.keys.size(); i++) { for (size_t i = 0; i < p.sf.keys.size(); i++) {
if (strcmp(key.c_str(), stringpool + pool_off[p.segment] + p.keys[i] + 1) == 0) { if (strcmp(key.c_str(), stringpool + pool_off[p.sf.segment] + p.sf.keys[i] + 1) == 0) {
serial_val sv; serial_val sv;
sv.s = stringpool + pool_off[p.segment] + p.values[i] + 1; sv.s = stringpool + pool_off[p.sf.segment] + p.sf.values[i] + 1;
sv.type = (stringpool + pool_off[p.segment])[p.values[i]]; sv.type = (stringpool + pool_off[p.sf.segment])[p.sf.values[i]];
p.full_keys.push_back(key); p.sf.full_keys.push_back(key);
p.full_values.push_back(sv); p.sf.full_values.push_back(sv);
p.keys.erase(p.keys.begin() + i); p.sf.keys.erase(p.sf.keys.begin() + i);
p.values.erase(p.values.begin() + i); p.sf.values.erase(p.sf.values.begin() + i);
break; break;
} }
} }
for (size_t i = 0; i < p.full_keys.size(); i++) { for (size_t i = 0; i < p.sf.full_keys.size(); i++) {
if (key == p.full_keys[i]) { if (key == p.sf.full_keys[i]) {
switch (op) { switch (op) {
case op_sum: case op_sum:
p.full_values[i].s = milo::dtoa_milo(atof(p.full_values[i].s.c_str()) + atof(val.s.c_str())); p.sf.full_values[i].s = milo::dtoa_milo(atof(p.sf.full_values[i].s.c_str()) + atof(val.s.c_str()));
p.full_values[i].type = mvt_double; p.sf.full_values[i].type = mvt_double;
break; break;
case op_product: case op_product:
p.full_values[i].s = milo::dtoa_milo(atof(p.full_values[i].s.c_str()) * atof(val.s.c_str())); p.sf.full_values[i].s = milo::dtoa_milo(atof(p.sf.full_values[i].s.c_str()) * atof(val.s.c_str()));
p.full_values[i].type = mvt_double; p.sf.full_values[i].type = mvt_double;
break; break;
case op_max: { case op_max: {
double existing = atof(p.full_values[i].s.c_str()); double existing = atof(p.sf.full_values[i].s.c_str());
double maybe = atof(val.s.c_str()); double maybe = atof(val.s.c_str());
if (maybe > existing) { if (maybe > existing) {
p.full_values[i].s = val.s.c_str(); p.sf.full_values[i].s = val.s.c_str();
p.full_values[i].type = mvt_double; p.sf.full_values[i].type = mvt_double;
} }
break; break;
} }
case op_min: { case op_min: {
double existing = atof(p.full_values[i].s.c_str()); double existing = atof(p.sf.full_values[i].s.c_str());
double maybe = atof(val.s.c_str()); double maybe = atof(val.s.c_str());
if (maybe < existing) { if (maybe < existing) {
p.full_values[i].s = val.s.c_str(); p.sf.full_values[i].s = val.s.c_str();
p.full_values[i].type = mvt_double; p.sf.full_values[i].type = mvt_double;
} }
break; break;
} }
@@ -1913,28 +1870,28 @@ void preserve_attribute(attribute_op op, serial_feature &, char *stringpool, lon
auto state = p.attribute_accum_state.find(key); auto state = p.attribute_accum_state.find(key);
if (state == p.attribute_accum_state.end()) { if (state == p.attribute_accum_state.end()) {
accum_state s; accum_state s;
s.sum = atof(p.full_values[i].s.c_str()) + atof(val.s.c_str()); s.sum = atof(p.sf.full_values[i].s.c_str()) + atof(val.s.c_str());
s.count = 2; s.count = 2;
p.attribute_accum_state.insert(std::pair<std::string, accum_state>(key, s)); p.attribute_accum_state.insert(std::pair<std::string, accum_state>(key, s));
p.full_values[i].s = milo::dtoa_milo(s.sum / s.count); p.sf.full_values[i].s = milo::dtoa_milo(s.sum / s.count);
} else { } else {
state->second.sum += atof(val.s.c_str()); state->second.sum += atof(val.s.c_str());
state->second.count += 1; state->second.count += 1;
p.full_values[i].s = milo::dtoa_milo(state->second.sum / state->second.count); p.sf.full_values[i].s = milo::dtoa_milo(state->second.sum / state->second.count);
} }
break; break;
} }
case op_concat: case op_concat:
p.full_values[i].s += val.s; p.sf.full_values[i].s += val.s;
p.full_values[i].type = mvt_string; p.sf.full_values[i].type = mvt_string;
break; break;
case op_comma: case op_comma:
p.full_values[i].s += std::string(",") + val.s; p.sf.full_values[i].s += std::string(",") + val.s;
p.full_values[i].type = mvt_string; p.sf.full_values[i].type = mvt_string;
break; break;
} }
} }
@@ -1967,11 +1924,11 @@ void preserve_attributes(std::map<std::string, attribute_op> const *attribute_ac
bool find_partial(std::vector<partial> &partials, serial_feature &sf, ssize_t &out, std::vector<std::vector<std::string>> *layer_unmaps, long long maxextent) { bool find_partial(std::vector<partial> &partials, serial_feature &sf, ssize_t &out, std::vector<std::vector<std::string>> *layer_unmaps, long long maxextent) {
for (size_t i = partials.size(); i > 0; i--) { for (size_t i = partials.size(); i > 0; i--) {
if (partials[i - 1].t == sf.t) { if (partials[i - 1].sf.t == sf.t) {
std::string &layername1 = (*layer_unmaps)[partials[i - 1].segment][partials[i - 1].layer]; std::string &layername1 = (*layer_unmaps)[partials[i - 1].sf.segment][partials[i - 1].sf.layer];
std::string &layername2 = (*layer_unmaps)[sf.segment][sf.layer]; std::string &layername2 = (*layer_unmaps)[sf.segment][sf.layer];
if (layername1 == layername2 && partials[i - 1].extent <= maxextent) { if (layername1 == layername2 && partials[i - 1].sf.extent <= maxextent) {
out = i - 1; out = i - 1;
return true; return true;
} }
@@ -2238,16 +2195,15 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
if ((sf.index < merge_previndex || sf.index - merge_previndex < mingap) && find_partial(partials, sf, which_partial, layer_unmaps, LLONG_MAX)) { if ((sf.index < merge_previndex || sf.index - merge_previndex < mingap) && find_partial(partials, sf, which_partial, layer_unmaps, LLONG_MAX)) {
partials[which_partial].clustered++; partials[which_partial].clustered++;
if (partials[which_partial].t == VT_POINT && if (partials[which_partial].sf.t == VT_POINT &&
partials[which_partial].geoms.size() == 1 && partials[which_partial].sf.geometry.size() == 1 &&
partials[which_partial].geoms[0].size() == 1 &&
sf.geometry.size() == 1) { sf.geometry.size() == 1) {
double x = (double) partials[which_partial].geoms[0][0].x * partials[which_partial].clustered; double x = (double) partials[which_partial].sf.geometry[0].x * partials[which_partial].clustered;
double y = (double) partials[which_partial].geoms[0][0].y * partials[which_partial].clustered; double y = (double) partials[which_partial].sf.geometry[0].y * partials[which_partial].clustered;
x += sf.geometry[0].x; x += sf.geometry[0].x;
y += sf.geometry[0].y; y += sf.geometry[0].y;
partials[which_partial].geoms[0][0].x = x / (partials[which_partial].clustered + 1); partials[which_partial].sf.geometry[0].x = x / (partials[which_partial].clustered + 1);
partials[which_partial].geoms[0][0].y = y / (partials[which_partial].clustered + 1); partials[which_partial].sf.geometry[0].y = y / (partials[which_partial].clustered + 1);
} }
preserve_attributes(arg->attribute_accum, sf, stringpool, pool_off, partials[which_partial]); preserve_attributes(arg->attribute_accum, sf, stringpool, pool_off, partials[which_partial]);
@@ -2268,7 +2224,9 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
indices.push_back(sf.index); indices.push_back(sf.index);
} }
if (sf.index - merge_previndex < mingap && find_partial(partials, sf, which_partial, layer_unmaps, LLONG_MAX)) { if (sf.index - merge_previndex < mingap && find_partial(partials, sf, which_partial, layer_unmaps, LLONG_MAX)) {
partials[which_partial].geoms.push_back(sf.geometry); for (auto &g : sf.geometry) {
partials[which_partial].sf.geometry.push_back(g);
}
partials[which_partial].coalesced = true; partials[which_partial].coalesced = true;
coalesced_area += sf.extent; coalesced_area += sf.extent;
preserve_attributes(arg->attribute_accum, sf, stringpool, pool_off, partials[which_partial]); preserve_attributes(arg->attribute_accum, sf, stringpool, pool_off, partials[which_partial]);
@@ -2287,7 +2245,9 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
} else if (additional[A_COALESCE_SMALLEST_AS_NEEDED]) { } else if (additional[A_COALESCE_SMALLEST_AS_NEEDED]) {
add_sample_to(extents, sf.extent, extents_increment, seq); add_sample_to(extents, sf.extent, extents_increment, seq);
if (sf.extent + coalesced_area <= minextent && find_partial(partials, sf, which_partial, layer_unmaps, minextent)) { if (sf.extent + coalesced_area <= minextent && find_partial(partials, sf, which_partial, layer_unmaps, minextent)) {
partials[which_partial].geoms.push_back(sf.geometry); for (auto &g : sf.geometry) {
partials[which_partial].sf.geometry.push_back(g);
}
partials[which_partial].coalesced = true; partials[which_partial].coalesced = true;
coalesced_area += sf.extent; coalesced_area += sf.extent;
preserve_attributes(arg->attribute_accum, sf, stringpool, pool_off, partials[which_partial]); preserve_attributes(arg->attribute_accum, sf, stringpool, pool_off, partials[which_partial]);
@@ -2311,7 +2271,9 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
fraction_accum += fraction; fraction_accum += fraction;
if (fraction_accum < 1 && find_partial(partials, sf, which_partial, layer_unmaps, LLONG_MAX)) { if (fraction_accum < 1 && find_partial(partials, sf, which_partial, layer_unmaps, LLONG_MAX)) {
if (additional[A_COALESCE_FRACTION_AS_NEEDED]) { if (additional[A_COALESCE_FRACTION_AS_NEEDED]) {
partials[which_partial].geoms.push_back(sf.geometry); for (auto &g : sf.geometry) {
partials[which_partial].sf.geometry.push_back(g);
}
partials[which_partial].coalesced = true; partials[which_partial].coalesced = true;
coalesced_area += sf.extent; coalesced_area += sf.extent;
strategy->coalesced_as_needed++; strategy->coalesced_as_needed++;
@@ -2379,10 +2341,8 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
for (; simplified_geometry_through < partials.size(); simplified_geometry_through++) { for (; simplified_geometry_through < partials.size(); simplified_geometry_through++) {
simplify_partial(&partials[simplified_geometry_through], dv); simplify_partial(&partials[simplified_geometry_through], dv);
for (auto &g : partials[simplified_geometry_through].geoms) { if (partials[simplified_geometry_through].sf.t == VT_POLYGON) {
if (partials[simplified_geometry_through].t == VT_POLYGON) { partials[simplified_geometry_through].sf.geometry = clean_or_clip_poly(partials[simplified_geometry_through].sf.geometry, 0, 0, false);
g = clean_or_clip_poly(g, 0, 0, false);
}
} }
} }
@@ -2418,37 +2378,37 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
partial &p = partials[i]; partial &p = partials[i];
if (p.clustered > 0) { if (p.clustered > 0) {
std::string layername = (*layer_unmaps)[p.segment][p.layer]; std::string layername = (*layer_unmaps)[p.sf.segment][p.sf.layer];
serial_val sv, sv2, sv3; serial_val sv, sv2, sv3;
p.full_keys.push_back("clustered"); p.sf.full_keys.push_back("clustered");
sv.type = mvt_bool; sv.type = mvt_bool;
sv.s = "true"; sv.s = "true";
p.full_values.push_back(sv); p.sf.full_values.push_back(sv);
add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, "clustered", sv); add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, "clustered", sv);
p.full_keys.push_back("point_count"); p.sf.full_keys.push_back("point_count");
sv2.type = mvt_double; sv2.type = mvt_double;
sv2.s = std::to_string(p.clustered + 1); sv2.s = std::to_string(p.clustered + 1);
p.full_values.push_back(sv2); p.sf.full_values.push_back(sv2);
add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, "point_count", sv2); add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, "point_count", sv2);
p.full_keys.push_back("sqrt_point_count"); p.sf.full_keys.push_back("sqrt_point_count");
sv3.type = mvt_double; sv3.type = mvt_double;
sv3.s = std::to_string(round(100 * sqrt(p.clustered + 1)) / 100.0); sv3.s = std::to_string(round(100 * sqrt(p.clustered + 1)) / 100.0);
p.full_values.push_back(sv3); p.sf.full_values.push_back(sv3);
add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, "sqrt_point_count", sv3); add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, "sqrt_point_count", sv3);
} }
if (p.need_tilestats.size() > 0) { if (p.need_tilestats.size() > 0) {
std::string layername = (*layer_unmaps)[p.segment][p.layer]; std::string layername = (*layer_unmaps)[p.sf.segment][p.sf.layer];
for (size_t j = 0; j < p.full_keys.size(); j++) { for (size_t j = 0; j < p.sf.full_keys.size(); j++) {
if (p.need_tilestats.count(p.full_keys[j]) > 0) { if (p.need_tilestats.count(p.sf.full_keys[j]) > 0) {
add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, p.full_keys[j], p.full_values[j]); add_tilestats(layername, z, layermaps, tiling_seg, layer_unmaps, p.sf.full_keys[j], p.sf.full_values[j]);
} }
} }
} }
@@ -2518,48 +2478,42 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
} }
for (size_t i = 0; i < partials.size(); i++) { for (size_t i = 0; i < partials.size(); i++) {
std::vector<drawvec> &pgeoms = partials[i].geoms; signed char t = partials[i].sf.t;
signed char t = partials[i].t; long long original_seq = partials[i].sf.seq;
long long original_seq = partials[i].original_seq;
// A complex polygon may have been split up into multiple geometries. if (t == VT_POINT || draws_something(partials[i].sf.geometry)) {
// Break them out into multiple features if necessary. struct coalesce c;
for (size_t j = 0; j < pgeoms.size(); j++) {
if (t == VT_POINT || draws_something(pgeoms[j])) {
struct coalesce c;
c.type = t; c.type = t;
c.index = partials[i].index; c.index = partials[i].sf.index;
c.geom = pgeoms[j]; c.geom = partials[i].sf.geometry;
pgeoms[j].clear(); c.coalesced = false;
c.coalesced = false; c.original_seq = partials[i].sf.seq;
c.original_seq = original_seq; c.stringpool = stringpool + pool_off[partials[i].sf.segment];
c.stringpool = stringpool + pool_off[partials[i].segment]; c.keys = partials[i].sf.keys;
c.keys = partials[i].keys; c.values = partials[i].sf.values;
c.values = partials[i].values; c.full_keys = partials[i].sf.full_keys;
c.full_keys = partials[i].full_keys; c.full_values = partials[i].sf.full_values;
c.full_values = partials[i].full_values; c.spacing = partials[i].spacing;
c.spacing = partials[i].spacing; c.id = partials[i].sf.id;
c.id = partials[i].id; c.has_id = partials[i].sf.has_id;
c.has_id = partials[i].has_id; c.extent = partials[i].sf.extent;
c.extent = partials[i].extent;
// printf("segment %d layer %lld is %s\n", partials[i].segment, partials[i].layer, (*layer_unmaps)[partials[i].segment][partials[i].layer].c_str()); // printf("segment %d layer %lld is %s\n", partials[i].segment, partials[i].layer, (*layer_unmaps)[partials[i].segment][partials[i].layer].c_str());
std::string layername = (*layer_unmaps)[partials[i].segment][partials[i].layer]; std::string layername = (*layer_unmaps)[partials[i].sf.segment][partials[i].sf.layer];
if (layers.count(layername) == 0) { if (layers.count(layername) == 0) {
layers.insert(std::pair<std::string, std::vector<coalesce>>(layername, std::vector<coalesce>())); layers.insert(std::pair<std::string, std::vector<coalesce>>(layername, std::vector<coalesce>()));
}
auto l = layers.find(layername);
if (l == layers.end()) {
fprintf(stderr, "Internal error: couldn't find layer %s\n", layername.c_str());
fprintf(stderr, "segment %d\n", partials[i].segment);
fprintf(stderr, "layer %lld\n", partials[i].layer);
exit(EXIT_IMPOSSIBLE);
}
l->second.push_back(c);
} }
auto l = layers.find(layername);
if (l == layers.end()) {
fprintf(stderr, "Internal error: couldn't find layer %s\n", layername.c_str());
fprintf(stderr, "segment %d\n", partials[i].sf.segment);
fprintf(stderr, "layer %lld\n", partials[i].sf.layer);
exit(EXIT_IMPOSSIBLE);
}
l->second.push_back(c);
} }
} }