mirror of
https://github.com/mapbox/tippecanoe.git
synced 2025-02-23 18:40:17 +00:00
Untested support for string feature IDs
This commit is contained in:
parent
b4cb2c6f5e
commit
bd186664ac
@ -105,6 +105,8 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
|
||||
|
||||
bool has_id = false;
|
||||
unsigned long long id_value = 0;
|
||||
bool has_string_id = false;
|
||||
std::string string_id_value;
|
||||
if (id != NULL) {
|
||||
if (id->type == JSON_NUMBER) {
|
||||
if (id->number >= 0) {
|
||||
@ -129,6 +131,9 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
|
||||
warned_neg = true;
|
||||
}
|
||||
}
|
||||
} else if (id->type == JSON_STRING) {
|
||||
has_string_id = true;
|
||||
string_id_value = id->string;
|
||||
} else {
|
||||
static bool warned_nan = false;
|
||||
|
||||
@ -194,6 +199,8 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
|
||||
sf.t = mb_geometry[t];
|
||||
sf.has_id = has_id;
|
||||
sf.id = id_value;
|
||||
sf.has_string_id = has_string_id;
|
||||
sf.string_id = string_id_value;
|
||||
sf.has_tippecanoe_minzoom = (tippecanoe_minzoom != -1);
|
||||
sf.tippecanoe_minzoom = tippecanoe_minzoom;
|
||||
sf.has_tippecanoe_maxzoom = (tippecanoe_maxzoom != -1);
|
||||
|
10
mvt.cpp
10
mvt.cpp
@ -303,6 +303,7 @@ bool mvt_tile::decode(std::string &message, bool &was_compressed) {
|
||||
std::vector<uint32_t> geoms;
|
||||
size_t dimensions = 0;
|
||||
std::vector<double> elevations;
|
||||
ssize_t string_id = -1;
|
||||
|
||||
while (feature_reader.next()) {
|
||||
switch (feature_reader.tag()) {
|
||||
@ -366,6 +367,12 @@ bool mvt_tile::decode(std::string &message, bool &was_compressed) {
|
||||
break;
|
||||
}
|
||||
|
||||
case 10: /* string id */
|
||||
{
|
||||
string_id = feature_reader.get_uint32();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
feature_reader.skip();
|
||||
break;
|
||||
@ -551,6 +558,9 @@ std::string mvt_tile::encode() {
|
||||
if (layers[i].features[f].has_id) {
|
||||
feature_writer.add_uint64(1, layers[i].features[f].id);
|
||||
}
|
||||
if (layers[i].features[f].string_id >= 0) {
|
||||
feature_writer.add_uint32(10, layers[i].features[f].string_id);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> geometry;
|
||||
|
||||
|
1
mvt.hpp
1
mvt.hpp
@ -63,6 +63,7 @@ struct mvt_feature {
|
||||
int /* mvt_geometry_type */ type = 0;
|
||||
unsigned long long id = 0;
|
||||
bool has_id = false;
|
||||
ssize_t string_id = -1;
|
||||
bool dropped = false;
|
||||
|
||||
// For use during decoding
|
||||
|
28
plugin.cpp
28
plugin.cpp
@ -214,8 +214,22 @@ std::vector<mvt_layer> parse_layers(int fd, int z, unsigned x, unsigned y, std::
|
||||
|
||||
json_object *id = json_hash_get(j, "id");
|
||||
if (id != NULL) {
|
||||
feature.id = atoll(id->string);
|
||||
feature.has_id = true;
|
||||
if (id->type == JSON_NUMBER) {
|
||||
feature.id = atoll(id->string);
|
||||
feature.has_id = true;
|
||||
} else if (id->type == JSON_STRING) {
|
||||
mvt_value val;
|
||||
val.type = mvt_string;
|
||||
val.string_value = id->string;
|
||||
|
||||
std::vector<unsigned long> onto;
|
||||
l->second.tag_v3_value(val, onto);
|
||||
if (onto.size() != 1) {
|
||||
fprintf(stderr, "Internal error: tagging a string value didn't have a length of 1\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
feature.string_id = onto[0];
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, layermap_entry> &layermap = (*layermaps)[tiling_seg];
|
||||
@ -411,6 +425,7 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
|
||||
sf.extent = 0;
|
||||
sf.metapos = 0;
|
||||
sf.has_id = false;
|
||||
sf.has_string_id = false;
|
||||
|
||||
std::string layername = "unknown";
|
||||
json_object *tippecanoe = json_hash_get(j, "tippecanoe");
|
||||
@ -460,8 +475,13 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
|
||||
|
||||
json_object *id = json_hash_get(j, "id");
|
||||
if (id != NULL) {
|
||||
sf.id = atoll(id->string);
|
||||
sf.has_id = true;
|
||||
if (id->type == JSON_NUMBER) {
|
||||
sf.id = atoll(id->string);
|
||||
sf.has_id = true;
|
||||
} else if (id->type == JSON_STRING) {
|
||||
sf.string_id = id->string;
|
||||
sf.has_string_id = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, layermap_entry> &layermap = (*layermaps)[tiling_seg];
|
||||
|
15
serial.cpp
15
serial.cpp
@ -239,7 +239,8 @@ void serialize_feature(FILE *geomfile, serial_feature *sf, std::atomic<long long
|
||||
serialize_byte(geomfile, sf->t, geompos, fname);
|
||||
|
||||
long long layer = 0;
|
||||
layer |= sf->layer << 6;
|
||||
layer |= sf->layer << 7;
|
||||
layer |= (sf->has_string_id << 6);
|
||||
layer |= (sf->seq != 0) << 5;
|
||||
layer |= (sf->index != 0) << 4;
|
||||
layer |= (sf->extent != 0) << 3;
|
||||
@ -260,6 +261,9 @@ void serialize_feature(FILE *geomfile, serial_feature *sf, std::atomic<long long
|
||||
if (sf->has_id) {
|
||||
serialize_ulong_long(geomfile, sf->id, geompos, fname);
|
||||
}
|
||||
if (sf->has_string_id) {
|
||||
serialize_string(geomfile, sf->string_id, geompos, fname);
|
||||
}
|
||||
|
||||
serialize_int(geomfile, sf->segment, geompos, fname);
|
||||
|
||||
@ -307,6 +311,7 @@ serial_feature deserialize_feature(FILE *geoms, std::atomic<long long> *geompos_
|
||||
sf.tippecanoe_maxzoom = -1;
|
||||
sf.id = 0;
|
||||
sf.has_id = false;
|
||||
sf.has_string_id = false;
|
||||
if (sf.layer & (1 << 1)) {
|
||||
deserialize_int_io(geoms, &sf.tippecanoe_minzoom, geompos_in);
|
||||
}
|
||||
@ -317,6 +322,10 @@ serial_feature deserialize_feature(FILE *geoms, std::atomic<long long> *geompos_
|
||||
sf.has_id = true;
|
||||
deserialize_ulong_long_io(geoms, &sf.id, geompos_in);
|
||||
}
|
||||
if (sf.layer & (1 << 6)) {
|
||||
sf.has_string_id = true;
|
||||
deserialize_string_io(geoms, sf.string_id, geompos_in);
|
||||
}
|
||||
|
||||
deserialize_int_io(geoms, &sf.segment, geompos_in);
|
||||
|
||||
@ -331,7 +340,7 @@ serial_feature deserialize_feature(FILE *geoms, std::atomic<long long> *geompos_
|
||||
deserialize_long_long_io(geoms, &sf.extent, geompos_in);
|
||||
}
|
||||
|
||||
sf.layer >>= 6;
|
||||
sf.layer >>= 7;
|
||||
|
||||
sf.metapos = 0;
|
||||
deserialize_long_long_io(geoms, &sf.metapos, geompos_in);
|
||||
@ -440,7 +449,7 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
|
||||
sf.geometry = fix_polygon(sf.geometry);
|
||||
}
|
||||
|
||||
if (!sf.has_id) {
|
||||
if (!sf.has_id && !sf.has_string_id) {
|
||||
if (additional[A_GENERATE_IDS]) {
|
||||
sf.has_id = true;
|
||||
sf.id = sf.seq + 1;
|
||||
|
@ -51,6 +51,8 @@ struct serial_feature {
|
||||
|
||||
bool has_id = false;
|
||||
unsigned long long id = 0;
|
||||
bool has_string_id = false;
|
||||
std::string string_id = "";
|
||||
|
||||
bool has_tippecanoe_minzoom = false;
|
||||
int tippecanoe_minzoom = 0;
|
||||
|
@ -180,6 +180,17 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::map<std::st
|
||||
v.type = mvt_uint;
|
||||
v.numeric_value.uint_value = feat.id;
|
||||
|
||||
attributes.insert(std::pair<std::string, mvt_value>("$id", v));
|
||||
} else if (feat.string_id >= 0) {
|
||||
if (feat.string_id >= (ssize_t) layer.string_values.string_values.size()) {
|
||||
fprintf(stderr, "Internal error: Out of bounds string ID reference\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mvt_value v;
|
||||
v.type = mvt_string;
|
||||
v.string_value = layer.string_values.string_values[feat.string_id];
|
||||
|
||||
attributes.insert(std::pair<std::string, mvt_value>("$id", v));
|
||||
}
|
||||
|
||||
@ -214,6 +225,26 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::map<std::st
|
||||
outfeature.has_id = true;
|
||||
outfeature.id = feat.id;
|
||||
}
|
||||
if (feat.string_id >= 0) {
|
||||
if (feat.string_id >= (ssize_t) layer.string_values.string_values.size()) {
|
||||
fprintf(stderr, "Internal error: Out of bounds string ID reference\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mvt_value v;
|
||||
v.type = mvt_string;
|
||||
v.string_value = layer.string_values.string_values[feat.string_id];
|
||||
|
||||
std::vector<unsigned long> onto;
|
||||
outlayer.tag_v3_value(v, onto);
|
||||
|
||||
if (onto.size() != 1) {
|
||||
fprintf(stderr, "Internal error: tagging string value didn't have size of 1\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
outfeature.string_id = onto[0];
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, mvt_value>> todo;
|
||||
|
||||
|
64
tile.cpp
64
tile.cpp
@ -85,6 +85,8 @@ struct coalesce {
|
||||
double spacing = 0;
|
||||
bool has_id = false;
|
||||
unsigned long long id = 0;
|
||||
bool has_string_id = false;
|
||||
std::string string_id;
|
||||
|
||||
bool operator<(const coalesce &o) const {
|
||||
int cmp = coalindexcmp(this, &o);
|
||||
@ -114,6 +116,9 @@ int coalcmp(const void *v1, const void *v2) {
|
||||
if (c1->has_id != c2->has_id) {
|
||||
return (int) c1->has_id - (int) c2->has_id;
|
||||
}
|
||||
if (c1->has_string_id != c2->has_string_id) {
|
||||
return (int) c1->has_string_id - (int) c2->has_string_id;
|
||||
}
|
||||
|
||||
if (c1->has_id && c2->has_id) {
|
||||
if (c1->id < c2->id) {
|
||||
@ -123,6 +128,14 @@ int coalcmp(const void *v1, const void *v2) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (c1->has_string_id && c2->has_string_id) {
|
||||
if (c1->string_id < c2->string_id) {
|
||||
return -1;
|
||||
}
|
||||
if (c1->string_id > c2->string_id) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
cmp = metacmp(c1->keys, c1->values, c1->stringpool, c2->keys, c2->values, c2->stringpool);
|
||||
if (cmp != 0) {
|
||||
@ -244,7 +257,7 @@ static int metacmp(const std::vector<long long> &keys1, const std::vector<long l
|
||||
}
|
||||
}
|
||||
|
||||
void rewrite(drawvec &geom, int z, int nextzoom, int maxzoom, long long *bbox, unsigned tx, unsigned ty, int buffer, int *within, std::atomic<long long> *geompos, FILE **geomfile, const char *fname, signed char t, int layer, long long metastart, signed char feature_minzoom, int child_shards, int max_zoom_increment, long long seq, int tippecanoe_minzoom, int tippecanoe_maxzoom, int segment, unsigned *initial_x, unsigned *initial_y, std::vector<long long> &metakeys, std::vector<long long> &metavals, bool has_id, unsigned long long id, unsigned long long index, long long extent) {
|
||||
void rewrite(drawvec &geom, int z, int nextzoom, int maxzoom, long long *bbox, unsigned tx, unsigned ty, int buffer, int *within, std::atomic<long long> *geompos, FILE **geomfile, const char *fname, signed char t, int layer, long long metastart, signed char feature_minzoom, int child_shards, int max_zoom_increment, long long seq, int tippecanoe_minzoom, int tippecanoe_maxzoom, int segment, unsigned *initial_x, unsigned *initial_y, std::vector<long long> &metakeys, std::vector<long long> &metavals, bool has_id, unsigned long long id, bool has_string_id, std::string string_id, unsigned long long index, long long extent) {
|
||||
if (geom.size() > 0 && (nextzoom <= maxzoom || additional[A_EXTEND_ZOOMS])) {
|
||||
int xo, yo;
|
||||
int span = 1 << (nextzoom - z);
|
||||
@ -330,6 +343,8 @@ void rewrite(drawvec &geom, int z, int nextzoom, int maxzoom, long long *bbox, u
|
||||
sf.t = t;
|
||||
sf.has_id = has_id;
|
||||
sf.id = id;
|
||||
sf.has_string_id = has_string_id;
|
||||
sf.string_id = string_id;
|
||||
sf.has_tippecanoe_minzoom = tippecanoe_minzoom != -1;
|
||||
sf.tippecanoe_minzoom = tippecanoe_minzoom;
|
||||
sf.has_tippecanoe_maxzoom = tippecanoe_maxzoom != -1;
|
||||
@ -373,7 +388,9 @@ struct partial {
|
||||
double simplification = 0;
|
||||
signed char t = 0;
|
||||
unsigned long long id = 0;
|
||||
std::string string_id;
|
||||
bool has_id = 0;
|
||||
bool has_string_id = 0;
|
||||
ssize_t renamed = 0;
|
||||
long long extent = 0;
|
||||
long long clustered = 0;
|
||||
@ -1340,7 +1357,7 @@ serial_feature next_feature(FILE *geoms, std::atomic<long long> *geompos_in, cha
|
||||
|
||||
if (*first_time && pass == 1) { /* only write out the next zoom once, even if we retry */
|
||||
if (sf.tippecanoe_maxzoom == -1 || sf.tippecanoe_maxzoom >= nextzoom) {
|
||||
rewrite(sf.geometry, z, nextzoom, maxzoom, sf.bbox, tx, ty, buffer, within, geompos, geomfile, fname, sf.t, sf.layer, sf.metapos, sf.feature_minzoom, child_shards, max_zoom_increment, sf.seq, sf.tippecanoe_minzoom, sf.tippecanoe_maxzoom, sf.segment, initial_x, initial_y, sf.keys, sf.values, sf.has_id, sf.id, sf.index, sf.extent);
|
||||
rewrite(sf.geometry, z, nextzoom, maxzoom, sf.bbox, tx, ty, buffer, within, geompos, geomfile, fname, sf.t, sf.layer, sf.metapos, sf.feature_minzoom, child_shards, max_zoom_increment, sf.seq, sf.tippecanoe_minzoom, sf.tippecanoe_maxzoom, sf.segment, initial_x, initial_y, sf.keys, sf.values, sf.has_id, sf.id, sf.has_string_id, sf.string_id, sf.index, sf.extent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1385,6 +1402,13 @@ serial_feature next_feature(FILE *geoms, std::atomic<long long> *geompos_in, cha
|
||||
|
||||
attributes.insert(std::pair<std::string, mvt_value>("$id", v));
|
||||
}
|
||||
if (sf.has_string_id) {
|
||||
mvt_value v;
|
||||
v.type = mvt_string;
|
||||
v.string_value = sf.string_id;
|
||||
|
||||
attributes.insert(std::pair<std::string, mvt_value>("$id", v));
|
||||
}
|
||||
|
||||
mvt_value v;
|
||||
v.type = mvt_string;
|
||||
@ -1501,6 +1525,22 @@ void *run_prefilter(void *v) {
|
||||
tmp_feature.has_id = sf.has_id;
|
||||
tmp_feature.dropped = sf.dropped;
|
||||
|
||||
if (sf.has_string_id) {
|
||||
mvt_value sv;
|
||||
sv.type = mvt_string;
|
||||
sv.string_value = sf.string_id;
|
||||
|
||||
std::vector<unsigned long> onto;
|
||||
tmp_layer.tag_v3_value(sv, onto);
|
||||
|
||||
if (onto.size() != 1) {
|
||||
fprintf(stderr, "Internal error: Expected 1 element from tagging string\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
tmp_feature.string_id = onto[0];
|
||||
}
|
||||
|
||||
// Offset from tile coordinates back to world coordinates
|
||||
unsigned sx = 0, sy = 0;
|
||||
if (rpa->z != 0) {
|
||||
@ -1969,6 +2009,8 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
|
||||
p.simplification = simplification;
|
||||
p.id = sf.id;
|
||||
p.has_id = sf.has_id;
|
||||
p.string_id = sf.string_id;
|
||||
p.has_string_id = sf.has_string_id;
|
||||
p.index = sf.index;
|
||||
p.renamed = -1;
|
||||
p.extent = sf.extent;
|
||||
@ -2108,6 +2150,8 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
|
||||
c.spacing = partials[i].spacing;
|
||||
c.id = partials[i].id;
|
||||
c.has_id = partials[i].has_id;
|
||||
c.string_id = partials[i].string_id;
|
||||
c.has_string_id = partials[i].has_string_id;
|
||||
|
||||
// printf("segment %d layer %lld is %s\n", partials[i].segment, partials[i].layer, (*layer_unmaps)[partials[i].segment][partials[i].layer].c_str());
|
||||
|
||||
@ -2226,6 +2270,22 @@ long long write_tile(FILE *geoms, std::atomic<long long> *geompos_in, char *meta
|
||||
feature.id = layer_features[x].id;
|
||||
feature.has_id = layer_features[x].has_id;
|
||||
|
||||
if (layer_features[x].has_string_id) {
|
||||
mvt_value sv;
|
||||
sv.type = mvt_string;
|
||||
sv.string_value = layer_features[x].string_id;
|
||||
|
||||
std::vector<unsigned long> onto;
|
||||
layer.tag_v3_value(sv, onto);
|
||||
|
||||
if (onto.size() != 1) {
|
||||
fprintf(stderr, "Internal error: Expected 1 element from tagging string\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
feature.string_id = onto[0];
|
||||
}
|
||||
|
||||
decode_meta(layer_features[x].keys, layer_features[x].values, layer_features[x].stringpool, layer, feature, true);
|
||||
|
||||
for (size_t a = 0; a < layer_features[x].full_keys.size(); a++) {
|
||||
|
@ -413,6 +413,14 @@ void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y
|
||||
state.json_write_string("id");
|
||||
state.json_write_unsigned(feat.id);
|
||||
}
|
||||
if (feat.string_id >= 0) {
|
||||
state.json_write_string("id");
|
||||
if (feat.string_id >= (ssize_t) layer.string_values.string_values.size()) {
|
||||
fprintf(stderr, "Internal error: out of bounds string ID reference\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
state.json_write_string(layer.string_values.string_values[feat.string_id]);
|
||||
}
|
||||
|
||||
if (name || zoom || index != 0 || sequence != 0 || extent != 0) {
|
||||
state.json_write_string("tippecanoe");
|
||||
|
Loading…
x
Reference in New Issue
Block a user