Use the standard JSON writer for tilestats

With a lot of weird special cases to keep the formatting
exactly like it accidentally was before
This commit is contained in:
Eric Fischer
2018-03-16 15:19:23 -07:00
parent 08fc2f281e
commit ebb0334ef0
3 changed files with 118 additions and 106 deletions
+2 -2
View File
@@ -56,7 +56,7 @@ tippecanoe-enumerate: enumerate.o
tippecanoe-decode: decode.o projection.o mvt.o write_json.o text.o jsonpull/jsonpull.o dirtiles.o tippecanoe-decode: decode.o projection.o mvt.o write_json.o text.o jsonpull/jsonpull.o dirtiles.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 $(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 evaluator.o csv.o tile-join: tile-join.o projection.o pool.o mbtiles.o mvt.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o evaluator.o csv.o write_json.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread $(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
tippecanoe-json-tool: jsontool.o jsonpull/jsonpull.o csv.o text.o tippecanoe-json-tool: jsontool.o jsonpull/jsonpull.o csv.o text.o
@@ -165,7 +165,7 @@ enumerate-test:
cmp tests/ne_110m_admin_0_countries/out/enum tests/ne_110m_admin_0_countries/out/enum.check cmp tests/ne_110m_admin_0_countries/out/enum tests/ne_110m_admin_0_countries/out/enum.check
rm tests/ne_110m_admin_0_countries/out/enum.mbtiles tests/ne_110m_admin_0_countries/out/enum.check rm tests/ne_110m_admin_0_countries/out/enum.mbtiles tests/ne_110m_admin_0_countries/out/enum.check
join-test: join-test: tile-join
./tippecanoe -f -z12 -o tests/join-population/tabblock_06001420.mbtiles tests/join-population/tabblock_06001420.json ./tippecanoe -f -z12 -o tests/join-population/tabblock_06001420.mbtiles tests/join-population/tabblock_06001420.json
./tippecanoe -f -Z5 -z10 -o tests/join-population/macarthur.mbtiles -l macarthur tests/join-population/macarthur.json ./tippecanoe -f -Z5 -z10 -o tests/join-population/macarthur.mbtiles -l macarthur tests/join-population/macarthur.json
./tile-join -f -Z6 -z9 -o tests/join-population/macarthur-6-9.mbtiles tests/join-population/macarthur.mbtiles ./tile-join -f -Z6 -z9 -o tests/join-population/macarthur-6-9.mbtiles tests/join-population/macarthur.mbtiles
+101 -95
View File
@@ -16,6 +16,7 @@
#include "mbtiles.hpp" #include "mbtiles.hpp"
#include "text.hpp" #include "text.hpp"
#include "milo/dtoa_milo.h" #include "milo/dtoa_milo.h"
#include "write_json.hpp"
sqlite3 *mbtiles_open(char *dbname, char **argv, int forcetable) { sqlite3 *mbtiles_open(char *dbname, char **argv, int forcetable) {
sqlite3 *outdb; sqlite3 *outdb;
@@ -139,36 +140,36 @@ bool type_and_string::operator!=(const type_and_string &o) const {
return false; return false;
} }
std::string tilestats(std::map<std::string, layermap_entry> const &layermap1, size_t elements) { void tilestats(std::map<std::string, layermap_entry> const &layermap1, size_t elements, json_writer &state) {
// Consolidate layers/attributes whose names are truncated // Consolidate layers/attributes whose names are truncated
std::vector<std::map<std::string, layermap_entry>> lmv; std::vector<std::map<std::string, layermap_entry>> lmv;
lmv.push_back(layermap1); lmv.push_back(layermap1);
std::map<std::string, layermap_entry> layermap = merge_layermaps(lmv, true); std::map<std::string, layermap_entry> layermap = merge_layermaps(lmv, true);
std::string out = "{\n"; state.json_write_hash();
out.append("\t\"layerCount\": "); state.nospace = true;
out.append(std::to_string(layermap.size())); state.json_write_string("layerCount");
out.append(",\n"); state.json_write_unsigned(layermap.size());
out.append("\t\"layers\": [\n"); state.nospace = true;
state.json_write_string("layers");
state.json_write_array();
bool first = true; bool first = true;
for (auto layer : layermap) { for (auto layer : layermap) {
if (!first) {
out.append(",\n");
}
first = false; first = false;
out.append("\t\t{\n"); state.nospace = true;
state.json_write_hash();
out.append("\t\t\t\"layer\": \""); state.nospace = true;
quote(out, layer.first.c_str()); state.json_write_string("layer");
out.append("\",\n"); state.json_write_string(layer.first);
out.append("\t\t\t\"count\": "); state.nospace = true;
out.append(std::to_string(layer.second.points + layer.second.lines + layer.second.polygons)); state.json_write_string("count");
out.append(",\n"); state.json_write_unsigned(layer.second.points + layer.second.lines + layer.second.polygons);
std::string geomtype = "Polygon"; std::string geomtype = "Polygon";
if (layer.second.points >= layer.second.lines && layer.second.points >= layer.second.polygons) { if (layer.second.points >= layer.second.lines && layer.second.points >= layer.second.polygons) {
@@ -177,45 +178,46 @@ std::string tilestats(std::map<std::string, layermap_entry> const &layermap1, si
geomtype = "LineString"; geomtype = "LineString";
} }
out.append("\t\t\t\"geometry\": \""); state.nospace = true;
quote(out, geomtype.c_str()); state.json_write_string("geometry");
out.append("\",\n"); state.json_write_string(geomtype);
size_t attrib_count = layer.second.file_keys.size(); size_t attrib_count = layer.second.file_keys.size();
if (attrib_count > 1000) { if (attrib_count > 1000) {
attrib_count = 1000; attrib_count = 1000;
} }
out.append("\t\t\t\"attributeCount\": "); state.nospace = true;
out.append(std::to_string(attrib_count)); state.json_write_string("attributeCount");
out.append(",\n"); state.json_write_unsigned(attrib_count);
out.append("\t\t\t\"attributes\": [\n"); state.nospace = true;
state.json_write_string("attributes");
state.nospace = true;
state.json_write_array();
size_t attrs = 0; size_t attrs = 0;
for (auto attribute : layer.second.file_keys) { for (auto attribute : layer.second.file_keys) {
if (attrs == elements) { if (attrs == elements) {
break; break;
} }
if (attrs != 0) {
out.append(",\n");
}
attrs++; attrs++;
out.append("\t\t\t\t{\n"); state.nospace = true;
state.json_write_hash();
out.append("\t\t\t\t\t\"attribute\": \""); state.nospace = true;
quote(out, attribute.first.c_str()); state.json_write_string("attribute");
out.append("\",\n"); state.json_write_string(attribute.first);
size_t val_count = attribute.second.sample_values.size(); size_t val_count = attribute.second.sample_values.size();
if (val_count > 1000) { if (val_count > 1000) {
val_count = 1000; val_count = 1000;
} }
out.append("\t\t\t\t\t\"count\": "); state.nospace = true;
out.append(std::to_string(val_count)); state.json_write_string("count");
out.append(",\n"); state.json_write_unsigned(val_count);
int type = 0; int type = 0;
for (auto s : attribute.second.sample_values) { for (auto s : attribute.second.sample_values) {
@@ -234,11 +236,13 @@ std::string tilestats(std::map<std::string, layermap_entry> const &layermap1, si
type_str = "mixed"; type_str = "mixed";
} }
out.append("\t\t\t\t\t\"type\": \""); state.nospace = true;
quote(out, type_str.c_str()); state.json_write_string("type");
out.append("\",\n"); state.json_write_string(type_str);
out.append("\t\t\t\t\t\"values\": [\n"); state.nospace = true;
state.json_write_string("values");
state.json_write_array();
size_t vals = 0; size_t vals = 0;
for (auto value : attribute.second.sample_values) { for (auto value : attribute.second.sample_values) {
@@ -246,65 +250,50 @@ std::string tilestats(std::map<std::string, layermap_entry> const &layermap1, si
break; break;
} }
state.nospace = true;
if (value.type == mvt_double || value.type == mvt_bool) { if (value.type == mvt_double || value.type == mvt_bool) {
if (vals != 0) {
out.append(",\n");
}
vals++; vals++;
out.append("\t\t\t\t\t\t"); state.json_write_stringified(value.string);
out.append(value.string);
} else { } else {
std::string trunc = truncate16(value.string, 256); std::string trunc = truncate16(value.string, 256);
if (trunc.size() == value.string.size()) { if (trunc.size() == value.string.size()) {
if (vals != 0) {
out.append(",\n");
}
vals++; vals++;
out.append("\t\t\t\t\t\t\""); state.json_write_string(value.string);
quote(out, value.string.c_str());
out.append("\"");
} }
} }
} }
out.append("\n"); state.nospace = true;
out.append("\t\t\t\t\t]"); state.json_end_array();
if ((type & (1 << mvt_double)) != 0) { if ((type & (1 << mvt_double)) != 0) {
out.append(",\n"); state.nospace = true;
state.json_write_string("min");
state.json_write_number(attribute.second.min);
out.append("\t\t\t\t\t\"min\": "); state.nospace = true;
out.append(milo::dtoa_milo(attribute.second.min)); state.json_write_string("max");
out.append(",\n"); state.json_write_number(attribute.second.max);
out.append("\t\t\t\t\t\"max\": ");
out.append(milo::dtoa_milo(attribute.second.max));
} }
out.append("\n"); state.nospace = true;
out.append("\t\t\t\t}"); state.json_end_hash();
} }
out.append("\n\t\t\t]\n"); state.nospace = true;
out.append("\t\t}"); state.json_end_array();
state.nospace = true;
state.json_end_hash();
} }
out.append("\n"); state.nospace = true;
out.append("\t]\n"); state.json_end_array();
out.append("}"); state.nospace = true;
state.json_end_hash();
std::string out2;
for (size_t i = 0; i < out.size(); i++) {
if (out[i] != '\t' && out[i] != '\n') {
out2.push_back(out[i]);
}
}
return out2;
} }
void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fname, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, int forcetable, const char *attribution, std::map<std::string, layermap_entry> const &layermap, bool vector, const char *description, bool do_tilestats) { void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fname, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, int forcetable, const char *attribution, std::map<std::string, layermap_entry> const &layermap, bool vector, const char *description, bool do_tilestats) {
@@ -419,8 +408,13 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
std::string buf; std::string buf;
{ {
buf = "{"; json_writer state(&buf);
aprintf(&buf, "\"vector_layers\": [ ");
state.json_write_hash();
state.nospace = true;
state.json_write_string("vector_layers");
state.json_write_array();
std::vector<std::string> lnames; std::vector<std::string> lnames;
for (auto ai = layermap.begin(); ai != layermap.end(); ++ai) { for (auto ai = layermap.begin(); ai != layermap.end(); ++ai) {
@@ -428,25 +422,32 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
} }
for (size_t i = 0; i < lnames.size(); i++) { for (size_t i = 0; i < lnames.size(); i++) {
if (i != 0) {
aprintf(&buf, ", ");
}
auto fk = layermap.find(lnames[i]); auto fk = layermap.find(lnames[i]);
aprintf(&buf, "{ \"id\": \""); state.json_write_hash();
quote(buf, lnames[i]);
aprintf(&buf, "\", \"description\": \"\", \"minzoom\": %d, \"maxzoom\": %d, \"fields\": {", fk->second.minzoom, fk->second.maxzoom); state.json_write_string("id");
state.json_write_string(lnames[i]);
state.json_write_string("description");
state.json_write_string("");
state.json_write_string("minzoom");
state.json_write_signed(fk->second.minzoom);
state.json_write_string("maxzoom");
state.json_write_signed(fk->second.maxzoom);
state.json_write_string("fields");
state.json_write_hash();
state.nospace = true;
bool first = true; bool first = true;
for (auto j = fk->second.file_keys.begin(); j != fk->second.file_keys.end(); ++j) { for (auto j = fk->second.file_keys.begin(); j != fk->second.file_keys.end(); ++j) {
if (first) { if (first) {
first = false; first = false;
} else {
aprintf(&buf, ", ");
} }
aprintf(&buf, "\""); state.json_write_string(j->first);
quote(buf, j->first.c_str());
int type = 0; int type = 0;
for (auto s : j->second.sample_values) { for (auto s : j->second.sample_values) {
@@ -454,26 +455,31 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
} }
if (type == (1 << mvt_double)) { if (type == (1 << mvt_double)) {
aprintf(&buf, "\": \"Number\""); state.json_write_string("Number");
} else if (type == (1 << mvt_bool)) { } else if (type == (1 << mvt_bool)) {
aprintf(&buf, "\": \"Boolean\""); state.json_write_string("Boolean");
} else if (type == (1 << mvt_string)) { } else if (type == (1 << mvt_string)) {
aprintf(&buf, "\": \"String\""); state.json_write_string("String");
} else { } else {
aprintf(&buf, "\": \"Mixed\""); state.json_write_string("Mixed");
} }
} }
aprintf(&buf, "} }"); state.nospace = true;
state.json_end_hash();
state.json_end_hash();
} }
aprintf(&buf, " ]"); state.json_end_array();
if (do_tilestats && elements > 0) { if (do_tilestats && elements > 0) {
aprintf(&buf, ",\"tilestats\": %s", tilestats(layermap, elements).c_str()); state.nospace = true;
state.json_write_string("tilestats");
tilestats(layermap, elements, state);
} }
aprintf(&buf, "}"); state.nospace = true;
state.json_end_hash();
} }
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('json', %Q);", buf.c_str()); sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('json', %Q);", buf.c_str());
+15 -9
View File
@@ -28,6 +28,9 @@ void json_writer::json_adjust() {
if (wantnl) { if (wantnl) {
adds(",\n"); adds(",\n");
nospace = false; nospace = false;
} else if (nospace) {
addc(',');
nospace = false;
} else { } else {
adds(", "); adds(", ");
} }
@@ -43,6 +46,9 @@ void json_writer::json_adjust() {
if (wantnl) { if (wantnl) {
adds(",\n"); adds(",\n");
nospace = false; nospace = false;
} else if (nospace) {
addc(',');
nospace = false;
} else { } else {
adds(", "); adds(", ");
} }
@@ -116,17 +122,17 @@ void json_writer::json_end_hash() {
} }
} }
void json_writer::json_write_string(std::string const &s) { void json_writer::json_write_string(std::string const &str) {
json_adjust(); json_adjust();
addc('"'); addc('"');
for (size_t i = 0; i < s.size(); i++) { for (size_t i = 0; i < str.size(); i++) {
if (s[i] == '\\' || s[i] == '"') { if (str[i] == '\\' || str[i] == '"') {
aprintf("\\%c", s[i]); aprintf("\\%c", str[i]);
} else if ((unsigned char) s[i] < ' ') { } else if ((unsigned char) str[i] < ' ') {
aprintf("\\u%04x", s[i]); aprintf("\\u%04x", str[i]);
} else { } else {
addc(s[i]); addc(str[i]);
} }
} }
addc('"'); addc('"');
@@ -157,10 +163,10 @@ void json_writer::json_write_signed(long long v) {
aprintf("%lld", v); aprintf("%lld", v);
} }
void json_writer::json_write_stringified(std::string const &s) { void json_writer::json_write_stringified(std::string const &str) {
json_adjust(); json_adjust();
adds(s); adds(str);
} }
void json_writer::json_write_bool(bool b) { void json_writer::json_write_bool(bool b) {