Fix and test round trip of compound attributes through tile-join

This commit is contained in:
Eric Fischer 2017-08-21 14:00:40 -07:00
parent c2b7d36b1f
commit 1ca0d0017e
8 changed files with 89 additions and 46 deletions

View File

@ -52,10 +52,10 @@ tippecanoe: geojson.o jsonpull/jsonpull.o tile.o pool.o mbtiles.o geometry.o pro
tippecanoe-enumerate: enumerate.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lsqlite3
tippecanoe-decode: decode.o projection.o mvt.o write_json.o
tippecanoe-decode: decode.o projection.o mvt.o write_json.o text.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3
tile-join: tile-join.o projection.o pool.o mbtiles.o mvt.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o
tile-join: tile-join.o projection.o pool.o mbtiles.o mvt.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o write_json.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
unit: unit.o text.o
@ -78,7 +78,7 @@ indent:
TESTS = $(wildcard tests/*/out/*.json)
SPACE = $(NULL) $(NULL)
test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test unit
test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test unit join-test-object
./unit
# Work around Makefile and filename punctuation limits: _ for space, @ for :, % for /
@ -199,6 +199,14 @@ join-test:
rm tests/join-population/tabblock_06001420.mbtiles tests/join-population/joined.mbtiles tests/join-population/joined-i.mbtiles tests/join-population/joined.mbtiles.json.check tests/join-population/joined-i.mbtiles.json.check tests/join-population/macarthur.mbtiles tests/join-population/merged.mbtiles tests/join-population/merged.mbtiles.json.check tests/join-population/merged-folder.mbtiles tests/join-population/macarthur2.mbtiles tests/join-population/windows.mbtiles tests/join-population/windows-merged.mbtiles tests/join-population/windows-merged2.mbtiles tests/join-population/windows.mbtiles.json.check tests/join-population/just-macarthur.mbtiles tests/join-population/no-macarthur.mbtiles tests/join-population/just-macarthur.mbtiles.json.check tests/join-population/no-macarthur.mbtiles.json.check tests/join-population/merged-folder.mbtiles.json.check tests/join-population/windows-merged.mbtiles.json.check tests/join-population/windows-merged2.mbtiles.json.check tests/join-population/macarthur-and-macarthur2-merged.mbtiles tests/join-population/macarthur-and-macarthur2-merged2.mbtiles tests/join-population/macarthur-and-macarthur2-merged.mbtiles.json.check tests/join-population/macarthur-and-macarthur2-merged2.mbtiles.json.check
rm -rf tests/join-population/raw-merged-folder tests/join-population/tabblock_06001420-folder tests/join-population/macarthur-folder tests/join-population/macarthur2-folder tests/join-population/merged-mbtiles-to-folder tests/join-population/merged-folders-to-folder tests/join-population/windows-merged-folder tests/join-population/macarthur-and-macarthur2-folder
join-test-object:
./tippecanoe -z0 -f -o tests/object/out/before.mbtiles tests/object/in.json
./tile-join -f -o tests/object/out/after.mbtiles tests/object/out/before.mbtiles
./tippecanoe-decode tests/object/out/before.mbtiles | grep -v '"bounds"' > tests/object/out/before.mbtiles.json
./tippecanoe-decode tests/object/out/after.mbtiles | grep -v '"bounds"' > tests/object/out/after.mbtiles.json
cmp tests/object/out/before.mbtiles.json tests/object/out/after.mbtiles.json
rm -f tests/object/out/before.mbtiles.json tests/object/out/after.mbtiles.json tests/object/out/before.mbtiles tests/object/out/after.mbtiles
# Use this target to regenerate the standards that the tests are compared against
# after making a change that legitimately changes their output

View File

@ -1,8 +1,3 @@
// for vasprintf() on Linux
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -102,21 +97,6 @@ static void quote(std::string &buf, std::string const &s) {
}
}
void aprintf(std::string *buf, const char *format, ...) {
va_list ap;
char *tmp;
va_start(ap, format);
if (vasprintf(&tmp, format, ap) < 0) {
fprintf(stderr, "memory allocation failure\n");
exit(EXIT_FAILURE);
}
va_end(ap);
buf->append(tmp, strlen(tmp));
free(tmp);
}
bool type_and_string::operator<(const type_and_string &o) const {
if (string < o.string) {
return true;

View File

@ -43,8 +43,6 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
void mbtiles_close(sqlite3 *outdb, const char *pgm);
void aprintf(std::string *buf, const char *format, ...);
std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::string, layermap_entry> > const &maps);
std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::string, layermap_entry> > const &maps, bool trunc);

View File

@ -1,5 +1,11 @@
// for vasprintf() on Linux
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "text.hpp"
#include <stdio.h>
#include <stdlib.h>
/**
* Returns an empty string if `s` is valid utf8;
@ -122,3 +128,18 @@ std::string truncate16(std::string const &s, size_t runes) {
return std::string(s, 0, lastgood - start);
}
void aprintf(std::string *buf, const char *format, ...) {
va_list ap;
char *tmp;
va_start(ap, format);
if (vasprintf(&tmp, format, ap) < 0) {
fprintf(stderr, "memory allocation failure\n");
exit(EXIT_FAILURE);
}
va_end(ap);
buf->append(tmp, strlen(tmp));
free(tmp);
}

View File

@ -6,5 +6,6 @@
std::string check_utf8(std::string text);
const char *utf8_next(const char *s, long *c);
std::string truncate16(std::string const &s, size_t runes);
void aprintf(std::string *buf, const char *format, ...);
#endif

View File

@ -22,6 +22,8 @@
#include "mbtiles.hpp"
#include "geometry.hpp"
#include "dirtiles.hpp"
#include "write_json.hpp"
#include "text.hpp"
#include <fstream>
#include <sstream>
#include <algorithm>
@ -171,6 +173,7 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::map<std::st
type = mvt_double;
} else if (val.type == mvt_null || val.type == mvt_list || val.type == mvt_hash) {
type = mvt_hash;
stringify_val(value, feat, layer, val, feat.tags[t + 1]);
} else {
continue;
}
@ -250,7 +253,12 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::map<std::st
auto fa = attributes.find(k);
if (fa != attributes.end()) {
outlayer.tag(outfeature, k, fa->second.first);
if (fa->second.first.type == mvt_hash) {
copy_nested(layer, feat, k, fa->second.first, outlayer, outfeature);
} else {
outlayer.tag(outfeature, k, fa->second.first);
}
add_to_file_keys(file_keys->second.file_keys, k, fa->second.second);
attributes.erase(fa);
}

View File

@ -7,6 +7,7 @@
#include "geometry.hpp"
#include "mvt.hpp"
#include "write_json.hpp"
#include "text.hpp"
struct lonlat {
int op;
@ -25,49 +26,74 @@ struct lonlat {
};
void print_val(FILE *fp, mvt_feature const &feature, mvt_layer const &layer, mvt_value const &val, size_t vo) {
std::string s;
stringify_val(s, feature, layer, val, vo);
fprintf(fp, "%s", s.c_str());
}
static void quote(std::string &buf, std::string const &s) {
buf.push_back('"');
for (size_t i = 0; i < s.size(); i++) {
unsigned char ch = s[i];
if (ch == '\\' || ch == '\"') {
buf.push_back('\\');
buf.push_back(ch);
} else if (ch < ' ') {
char tmp[7];
sprintf(tmp, "\\u%04x", ch);
buf.append(std::string(tmp));
} else {
buf.push_back(ch);
}
}
buf.push_back('"');
}
void stringify_val(std::string &out, mvt_feature const &feature, mvt_layer const &layer, mvt_value const &val, size_t vo) {
if (val.type == mvt_string) {
fprintq(fp, val.string_value.c_str());
quote(out, val.string_value);
} else if (val.type == mvt_int) {
fprintf(fp, "%lld", (long long) val.numeric_value.int_value);
out.append(std::to_string((long long) val.numeric_value.int_value));
} else if (val.type == mvt_double) {
double v = val.numeric_value.double_value;
if (v == (long long) v) {
fprintf(fp, "%lld", (long long) v);
out.append(std::to_string((long long) v));
} else {
fprintf(fp, "%g", v);
aprintf(&out, "%g", v);
}
} else if (val.type == mvt_float) {
double v = val.numeric_value.float_value;
if (v == (long long) v) {
fprintf(fp, "%lld", (long long) v);
out.append(std::to_string((long long) v));
} else {
fprintf(fp, "%g", v);
aprintf(&out, "%g", v);
}
} else if (val.type == mvt_sint) {
fprintf(fp, "%lld", (long long) val.numeric_value.sint_value);
out.append(std::to_string((long long) val.numeric_value.sint_value));
} else if (val.type == mvt_uint) {
fprintf(fp, "%lld", (long long) val.numeric_value.uint_value);
out.append(std::to_string((long long) val.numeric_value.uint_value));
} else if (val.type == mvt_bool) {
fprintf(fp, "%s", val.numeric_value.bool_value ? "true" : "false");
out.append(val.numeric_value.bool_value ? "true" : "false");
} else if (val.type == mvt_list) {
fprintf(fp, "[");
out.push_back('[');
for (size_t i = 0; i < val.list_value.size(); i++) {
if (i != 0) {
fprintf(fp, ",");
out.push_back(',');
}
if (val.list_value[i] >= vo || val.list_value[i] >= layer.values.size()) {
fprintf(stderr, "Invalid value reference in list (%lu from %lu within %lu)\n", val.list_value[i], vo,
layer.values.size());
exit(EXIT_FAILURE);
}
print_val(fp, feature, layer, layer.values[val.list_value[i]], val.list_value[i]);
stringify_val(out, feature, layer, layer.values[val.list_value[i]], val.list_value[i]);
}
fprintf(fp, "]");
out.push_back(']');
} else if (val.type == mvt_hash) {
fprintf(fp, "{");
out.push_back('{');
for (size_t i = 0; i + 1 < val.list_value.size(); i += 2) {
if (i != 0) {
fprintf(fp, ",");
out.push_back(',');
}
if (val.list_value[i] >= layer.keys.size()) {
fprintf(stderr, "Invalid key reference in hash (%lu from %lu within %lu)\n", val.list_value[i], vo, layer.keys.size());
@ -78,13 +104,13 @@ void print_val(FILE *fp, mvt_feature const &feature, mvt_layer const &layer, mvt
vo, layer.values.size());
exit(EXIT_FAILURE);
}
fprintq(fp, layer.keys[val.list_value[i]].c_str());
fprintf(fp, ":");
print_val(fp, feature, layer, layer.values[val.list_value[i + 1]], val.list_value[i + 1]);
quote(out, layer.keys[val.list_value[i]]);
out.push_back(':');
stringify_val(out, feature, layer, layer.values[val.list_value[i + 1]], val.list_value[i + 1]);
}
fprintf(fp, "}");
out.push_back('}');
} else if (val.type == mvt_null) {
fprintf(fp, "null");
out.append("null");
}
}

View File

@ -1,2 +1,3 @@
void layer_to_geojson(FILE *fp, mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, bool zoom, unsigned long long index, long long sequence, long long extent, bool complain);
void fprintq(FILE *f, const char *s);
void stringify_val(std::string &out, mvt_feature const &feature, mvt_layer const &layer, mvt_value const &val, size_t vo);