Merge pull request #298 from mapbox/tile-join-merge

Give tile-join the ability to merge multiple tilesets
This commit is contained in:
Eric Fischer 2016-09-20 16:53:46 -07:00 committed by GitHub
commit 4912f4ad08
14 changed files with 3903 additions and 136 deletions

View File

@ -1,3 +1,7 @@
## 1.14.0
* Tile-join is multithreaded and can merge multiple vector mbtiles files together
## 1.13.0
* Add the ability to specify layer names within the GeoJSON input

View File

@ -54,7 +54,7 @@ tippecanoe-decode: decode.o projection.o mvt.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
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
%.o: %.c $(ALL_H)
$(CC) $(PG) $(INCLUDES) $(FINAL_FLAGS) $(CFLAGS) -c -o $@ $<
@ -112,14 +112,20 @@ pbf-test:
rm tests/pbf/11-328-791.3857.vector.pbf.out
join-test:
./tippecanoe -f -z9 -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 -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 -d10 -D10 -Z9 -z11 -o tests/join-population/macarthur2.mbtiles -l macarthur tests/join-population/macarthur2.json
./tile-join -f -o tests/join-population/joined.mbtiles -x GEOID10 -c tests/join-population/population.csv tests/join-population/tabblock_06001420.mbtiles
./tile-join -f -i -o tests/join-population/joined-i.mbtiles -x GEOID10 -c tests/join-population/population.csv tests/join-population/tabblock_06001420.mbtiles
./tile-join -f -o tests/join-population/merged.mbtiles tests/join-population/tabblock_06001420.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tippecanoe-decode tests/join-population/joined.mbtiles > tests/join-population/joined.mbtiles.json.check
./tippecanoe-decode tests/join-population/joined-i.mbtiles > tests/join-population/joined-i.mbtiles.json.check
./tippecanoe-decode tests/join-population/merged.mbtiles > tests/join-population/merged.mbtiles.json.check
cmp tests/join-population/joined.mbtiles.json.check tests/join-population/joined.mbtiles.json
cmp tests/join-population/joined-i.mbtiles.json.check tests/join-population/joined-i.mbtiles.json
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
cmp tests/join-population/merged.mbtiles.json.check tests/join-population/merged.mbtiles.json
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/macarthur2.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

@ -285,6 +285,10 @@ Tile-join is a tool for joining new attributes from a CSV file to features that
have already been tiled with tippecanoe. It reads the tiles from an existing .mbtiles
file, matches them against the records of the CSV, and writes out a new tileset.
If you specify multiple source mbtiles files, they are all read and their combined
contents are written to the new mbtiles output. If they define the same layers or
the same tiles, the layers or tiles are merged.
The options are:
* -o *out.mbtiles*: Write the new tiles to the specified .mbtiles file
@ -292,10 +296,12 @@ The options are:
* -c *match.csv*: Use *match.csv* as the source for new attributes to join to the features. The first line of the file should be the key names; the other lines are values. The first column is the one to match against the existing features; the other columns are the new data to add.
* -x *key*: Remove attributes of type *key* from the output. You can use this to remove the field you are matching against if you no longer need it after joining, or to remove any other attributes you don't want.
* -i: Only include features that matched the CSV.
* -pk: Don't skip tiles larger than 500K.
Because tile-join just copies the geometries to the new .mbtiles without processing them,
Because tile-join just copies the geometries to the new .mbtiles without processing them
(except to rescale the extents if necessary),
it doesn't have any of tippecanoe's recourses if the new tiles are bigger than the 500K tile limit.
If a tile is too big, it is just left out of the new tileset.
If a tile is too big and you haven't specified `-pk`, it is just left out of the new tileset.
Example
-------

View File

@ -856,37 +856,6 @@ void radix(struct reader *reader, int nreaders, FILE *geomfile, int geomfd, FILE
}
}
std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::string, layermap_entry> > const &maps) {
std::map<std::string, layermap_entry> out;
for (size_t i = 0; i < maps.size(); i++) {
for (auto map = maps[i].begin(); map != maps[i].end(); ++map) {
if (out.count(map->first) == 0) {
out.insert(std::pair<std::string, layermap_entry>(map->first, layermap_entry(out.size())));
}
auto out_entry = out.find(map->first);
if (out_entry == out.end()) {
fprintf(stderr, "Internal error merging layers\n");
exit(EXIT_FAILURE);
}
for (auto fk = map->second.file_keys.begin(); fk != map->second.file_keys.end(); ++fk) {
out_entry->second.file_keys.insert(*fk);
}
if (additional[A_CALCULATE_FEATURE_DENSITY]) {
type_and_string tas;
tas.type = VT_NUMBER;
tas.string = "tippecanoe_feature_density";
out_entry->second.file_keys.insert(tas);
}
}
}
return out;
}
int read_input(std::vector<source> &sources, char *fname, const char *layername, int maxzoom, int minzoom, int basezoom, double basezoom_marker_width, sqlite3 *outdb, std::set<std::string> *exclude, std::set<std::string> *include, int exclude_all, double droprate, int buffer, const char *tmpdir, double gamma, int read_parallel, int forcetable, const char *attribution) {
int ret = EXIT_SUCCESS;
@ -1728,7 +1697,19 @@ int read_input(std::vector<source> &sources, char *fname, const char *layername,
}
std::map<std::string, layermap_entry> merged_lm = merge_layermaps(layermaps);
if (additional[A_CALCULATE_FEATURE_DENSITY]) {
for (auto ai = merged_lm.begin(); ai != merged_lm.end(); ++ai) {
type_and_string tas;
tas.type = VT_NUMBER;
tas.string = "tippecanoe_feature_density";
ai->second.file_keys.insert(tas);
}
}
for (auto ai = merged_lm.begin(); ai != merged_lm.end(); ++ai) {
ai->second.minzoom = minzoom;
ai->second.maxzoom = maxzoom;
}
mbtiles_write_metadata(outdb, fname, minzoom, maxzoom, minlat, minlon, maxlat, maxlon, midlat, midlon, forcetable, attribution, merged_lm);
return ret;

View File

@ -119,7 +119,7 @@ resolution is obtained than by using a smaller \fImaxzoom\fP or \fIdetail\fP\&.
.SS Point simplification
.RS
.IP \(bu 2
\-r \fIrate\fP or \-\-drop\fIrate=\fPrate_: Rate at which dots are dropped at zoom levels below basezoom (default 2.5).
\-r \fIrate\fP or \-\-drop\-rate=\fIrate\fP: Rate at which dots are dropped at zoom levels below basezoom (default 2.5).
If you use \-rg, it will guess a drop rate that will keep at most 50,000 features in the densest tile.
You can also specify a marker\-width with \-rg\fIwidth\fP to allow fewer features in the densest tile to
compensate for the larger marker, or \-rf\fInumber\fP to allow at most \fInumber\fP features in the densest tile.
@ -327,6 +327,10 @@ Tile\-join is a tool for joining new attributes from a CSV file to features that
have already been tiled with tippecanoe. It reads the tiles from an existing .mbtiles
file, matches them against the records of the CSV, and writes out a new tileset.
.PP
If you specify multiple source mbtiles files, they are all read and their combined
contents are written to the new mbtiles output. If they define the same layers or
the same tiles, the layers or tiles are merged.
.PP
The options are:
.RS
.IP \(bu 2
@ -339,11 +343,14 @@ The options are:
\-x \fIkey\fP: Remove attributes of type \fIkey\fP from the output. You can use this to remove the field you are matching against if you no longer need it after joining, or to remove any other attributes you don't want.
.IP \(bu 2
\-i: Only include features that matched the CSV.
.IP \(bu 2
\-pk: Don't skip tiles larger than 500K.
.RE
.PP
Because tile\-join just copies the geometries to the new .mbtiles without processing them,
Because tile\-join just copies the geometries to the new .mbtiles without processing them
(except to rescale the extents if necessary),
it doesn't have any of tippecanoe's recourses if the new tiles are bigger than the 500K tile limit.
If a tile is too big, it is just left out of the new tileset.
If a tile is too big and you haven't specified \fB\fC\-pk\fR, it is just left out of the new tileset.
.SH Example
.PP
Imagine you have a tileset of census blocks:

View File

@ -242,11 +242,11 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *fname, int minzoom, int
aprintf(&buf, ", ");
}
auto fk = layermap.find(lnames[i]);
aprintf(&buf, "{ \"id\": \"");
quote(&buf, lnames[i].c_str());
aprintf(&buf, "\", \"description\": \"\", \"minzoom\": %d, \"maxzoom\": %d, \"fields\": {", minzoom, maxzoom);
aprintf(&buf, "\", \"description\": \"\", \"minzoom\": %d, \"maxzoom\": %d, \"fields\": {", fk->second.minzoom, fk->second.maxzoom);
auto fk = layermap.find(lnames[i]);
std::set<type_and_string>::iterator j;
bool first = true;
for (j = fk->second.file_keys.begin(); j != fk->second.file_keys.end(); ++j) {
@ -295,3 +295,37 @@ void mbtiles_close(sqlite3 *outdb, char **argv) {
exit(EXIT_FAILURE);
}
}
std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::string, layermap_entry> > const &maps) {
std::map<std::string, layermap_entry> out;
for (size_t i = 0; i < maps.size(); i++) {
for (auto map = maps[i].begin(); map != maps[i].end(); ++map) {
if (out.count(map->first) == 0) {
out.insert(std::pair<std::string, layermap_entry>(map->first, layermap_entry(out.size())));
auto out_entry = out.find(map->first);
out_entry->second.minzoom = map->second.minzoom;
out_entry->second.maxzoom = map->second.maxzoom;
}
auto out_entry = out.find(map->first);
if (out_entry == out.end()) {
fprintf(stderr, "Internal error merging layers\n");
exit(EXIT_FAILURE);
}
for (auto fk = map->second.file_keys.begin(); fk != map->second.file_keys.end(); ++fk) {
out_entry->second.file_keys.insert(*fk);
}
if (map->second.minzoom < out_entry->second.minzoom) {
out_entry->second.minzoom = map->second.minzoom;
}
if (map->second.maxzoom > out_entry->second.maxzoom) {
out_entry->second.maxzoom = map->second.maxzoom;
}
}
}
return out;
}

View File

@ -8,6 +8,8 @@ struct type_and_string {
struct layermap_entry {
size_t id;
std::set<type_and_string> file_keys;
int minzoom;
int maxzoom;
layermap_entry(size_t _id) {
id = _id;
@ -23,3 +25,5 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *fname, int minzoom, int
void mbtiles_close(sqlite3 *outdb, char **argv);
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);

View File

@ -3,7 +3,7 @@
"center": "-122.299805,37.892187,12",
"description": "tests/join-population/joined-i.mbtiles",
"format": "pbf",
"json": "{\"vector_layers\": [ { \"id\": \"tabblock_06001420\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 12, \"fields\": {\"ALAND10\": \"Number\", \"AWATER10\": \"Number\", \"BLOCKCE10\": \"String\", \"COUNTYFP10\": \"String\", \"FUNCSTAT10\": \"String\", \"INTPTLAT10\": \"String\", \"INTPTLON10\": \"String\", \"MTFCC10\": \"String\", \"NAME10\": \"String\", \"STATEFP10\": \"String\", \"TRACTCE10\": \"String\", \"UACE10\": \"String\", \"UATYP10\": \"String\", \"UR10\": \"String\", \"population\": \"Number\"} } ] }",
"json": "{\"vector_layers\": [ { \"id\": \"tabblock_06001420\", \"description\": \"\", \"minzoom\": 3, \"maxzoom\": 12, \"fields\": {\"ALAND10\": \"Number\", \"AWATER10\": \"Number\", \"BLOCKCE10\": \"String\", \"COUNTYFP10\": \"String\", \"FUNCSTAT10\": \"String\", \"INTPTLAT10\": \"String\", \"INTPTLON10\": \"String\", \"MTFCC10\": \"String\", \"NAME10\": \"String\", \"STATEFP10\": \"String\", \"TRACTCE10\": \"String\", \"UACE10\": \"String\", \"UATYP10\": \"String\", \"UR10\": \"String\", \"population\": \"Number\"} } ] }",
"maxzoom": "12",
"minzoom": "0",
"name": "tests/join-population/joined-i.mbtiles",

View File

@ -3,7 +3,7 @@
"center": "-122.299805,37.892187,12",
"description": "tests/join-population/joined.mbtiles",
"format": "pbf",
"json": "{\"vector_layers\": [ { \"id\": \"tabblock_06001420\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 12, \"fields\": {\"ALAND10\": \"Number\", \"AWATER10\": \"Number\", \"BLOCKCE10\": \"String\", \"COUNTYFP10\": \"String\", \"FUNCSTAT10\": \"String\", \"INTPTLAT10\": \"String\", \"INTPTLON10\": \"String\", \"MTFCC10\": \"String\", \"NAME10\": \"String\", \"STATEFP10\": \"String\", \"TRACTCE10\": \"String\", \"UACE10\": \"String\", \"UATYP10\": \"String\", \"UR10\": \"String\", \"population\": \"Number\"} } ] }",
"json": "{\"vector_layers\": [ { \"id\": \"tabblock_06001420\", \"description\": \"\", \"minzoom\": 3, \"maxzoom\": 12, \"fields\": {\"ALAND10\": \"Number\", \"AWATER10\": \"Number\", \"BLOCKCE10\": \"String\", \"COUNTYFP10\": \"String\", \"FUNCSTAT10\": \"String\", \"INTPTLAT10\": \"String\", \"INTPTLON10\": \"String\", \"MTFCC10\": \"String\", \"NAME10\": \"String\", \"STATEFP10\": \"String\", \"TRACTCE10\": \"String\", \"UACE10\": \"String\", \"UATYP10\": \"String\", \"UR10\": \"String\", \"population\": \"Number\"} } ] }",
"maxzoom": "12",
"minzoom": "0",
"name": "tests/join-population/joined.mbtiles",

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
{ "type": "Feature", "properties": { "LINEARID": "1102406970092", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.181167, 37.774877 ], [ -122.180664, 37.774576 ], [ -122.18036, 37.774387 ], [ -122.180165, 37.774257 ], [ -122.179729, 37.773893 ], [ -122.179651, 37.773837 ], [ -122.17942, 37.773669 ], [ -122.179344, 37.773613 ], [ -122.179207, 37.773505 ], [ -122.178796, 37.773182 ], [ -122.178659, 37.773075 ], [ -122.178518, 37.772972 ], [ -122.178097, 37.772665 ], [ -122.177957, 37.772563 ], [ -122.177671, 37.772263 ], [ -122.177345, 37.771919 ], [ -122.176949, 37.77153 ], [ -122.176807, 37.77141 ], [ -122.176786, 37.771393 ], [ -122.17671, 37.771333 ], [ -122.1766, 37.771262 ], [ -122.176438, 37.771173 ], [ -122.176241, 37.771083 ], [ -122.175654, 37.770816 ], [ -122.175458, 37.770727 ], [ -122.173238, 37.769659 ], [ -122.173135, 37.769667 ], [ -122.172807, 37.769528 ], [ -122.172384, 37.769347 ], [ -122.172, 37.769173 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1104469713187", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.24151, 37.807276 ], [ -122.241474, 37.80724 ], [ -122.241437, 37.807195 ], [ -122.241405, 37.807159 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1104469713198", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.24151, 37.807276 ], [ -122.241663, 37.807503 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105089465114", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.169767, 37.767562 ], [ -122.169167, 37.767123 ], [ -122.168343, 37.766551 ], [ -122.168223, 37.766451 ], [ -122.168101, 37.766349 ], [ -122.167894, 37.766123 ], [ -122.167789, 37.766009 ], [ -122.167676, 37.765878 ], [ -122.167339, 37.765488 ], [ -122.167253, 37.765388 ], [ -122.167227, 37.765358 ], [ -122.167101, 37.765215 ], [ -122.166723, 37.764786 ], [ -122.166598, 37.764644 ], [ -122.166509, 37.764539 ], [ -122.166244, 37.764227 ], [ -122.166156, 37.764123 ], [ -122.166007, 37.763946 ], [ -122.165906, 37.763841 ], [ -122.165749, 37.763678 ], [ -122.165179, 37.762977 ], [ -122.164942, 37.762685 ], [ -122.164902, 37.762642 ], [ -122.164833, 37.762567 ], [ -122.16451, 37.762213 ], [ -122.164403, 37.762096 ], [ -122.164301, 37.761981 ], [ -122.163997, 37.761638 ], [ -122.163896, 37.761524 ], [ -122.163802, 37.761416 ], [ -122.16352, 37.761094 ], [ -122.163427, 37.760987 ], [ -122.163418, 37.760974 ], [ -122.163341, 37.760856 ], [ -122.163266, 37.760722 ], [ -122.163188, 37.760559 ], [ -122.16308, 37.760261 ], [ -122.162254, 37.757984 ], [ -122.161979, 37.757225 ], [ -122.161696, 37.756443 ], [ -122.161529, 37.755975 ], [ -122.161409, 37.755639 ], [ -122.161383, 37.755574 ], [ -122.161299, 37.75537 ], [ -122.161017, 37.754596 ], [ -122.160873, 37.754201 ], [ -122.160728, 37.753804 ], [ -122.1604, 37.752903 ], [ -122.160236, 37.752453 ], [ -122.159925, 37.751596 ], [ -122.159831, 37.751335 ], [ -122.159798, 37.751281 ], [ -122.159724, 37.751169 ], [ -122.159503, 37.750835 ], [ -122.15943, 37.750724 ], [ -122.159326, 37.750564 ], [ -122.159014, 37.750084 ], [ -122.158911, 37.749925 ], [ -122.158851, 37.749826 ], [ -122.158737, 37.749655 ], [ -122.158701, 37.749601 ], [ -122.15842, 37.749178 ], [ -122.158208, 37.748853 ], [ -122.158033, 37.748585 ], [ -122.157984, 37.748511 ], [ -122.157839, 37.748289 ], [ -122.157791, 37.748216 ], [ -122.157679, 37.748047 ], [ -122.157345, 37.747542 ], [ -122.157234, 37.747374 ], [ -122.156998, 37.747005 ], [ -122.156779, 37.74667 ], [ -122.156672, 37.746502 ], [ -122.156497, 37.746226 ], [ -122.156395, 37.746081 ], [ -122.156328, 37.74602 ], [ -122.156288, 37.745983 ], [ -122.156221, 37.745929 ], [ -122.156174, 37.745897 ], [ -122.155957, 37.745752 ], [ -122.155902, 37.745715 ], [ -122.155309, 37.745319 ], [ -122.155094, 37.745175 ], [ -122.154828, 37.744986 ], [ -122.154793, 37.744962 ], [ -122.154362, 37.744667 ], [ -122.154048, 37.744428 ], [ -122.153902, 37.74431 ], [ -122.153831, 37.744253 ], [ -122.153625, 37.744069 ], [ -122.153479, 37.743929 ], [ -122.153433, 37.743885 ], [ -122.153057, 37.743493 ], [ -122.152918, 37.743348 ], [ -122.152835, 37.743261 ], [ -122.152719, 37.743139 ], [ -122.152584, 37.743004 ], [ -122.152546, 37.742966 ], [ -122.152496, 37.742923 ], [ -122.152445, 37.742883 ], [ -122.152295, 37.742763 ], [ -122.152245, 37.742723 ], [ -122.152143, 37.742645 ], [ -122.151838, 37.742412 ], [ -122.151731, 37.742343 ], [ -122.151615, 37.742273 ], [ -122.151526, 37.742214 ], [ -122.151474, 37.742181 ], [ -122.15127, 37.742067 ], [ -122.150888, 37.74187 ], [ -122.150835, 37.741843 ], [ -122.150668, 37.741772 ], [ -122.150475, 37.74168 ], [ -122.149896, 37.741406 ], [ -122.149703, 37.741315 ], [ -122.14953, 37.741232 ], [ -122.149083, 37.741019 ], [ -122.149011, 37.740986 ], [ -122.148837, 37.740907 ], [ -122.148814, 37.740897 ], [ -122.148747, 37.740868 ], [ -122.148725, 37.740859 ], [ -122.148602, 37.740808 ], [ -122.148582, 37.7408 ], [ -122.148244, 37.740632 ], [ -122.148126, 37.740573 ], [ -122.148067, 37.740542 ], [ -122.147893, 37.740452 ], [ -122.147835, 37.740422 ], [ -122.147631, 37.740329 ], [ -122.147524, 37.740279 ], [ -122.146597, 37.739842 ], [ -122.146289, 37.739697 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1103717593123", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.227829, 37.801353 ], [ -122.227647, 37.80132 ], [ -122.226894, 37.801189 ], [ -122.226004, 37.801027 ], [ -122.225716, 37.800984 ], [ -122.224948, 37.800841 ], [ -122.223877, 37.800642 ], [ -122.222965, 37.800478 ], [ -122.222828, 37.800448 ], [ -122.220734, 37.800069 ], [ -122.220416, 37.800015 ], [ -122.220292, 37.8 ], [ -122.220191, 37.799998 ], [ -122.220097, 37.800013 ], [ -122.22005, 37.800028 ], [ -122.21997, 37.800068 ], [ -122.219852, 37.800141 ], [ -122.21977, 37.800202 ], [ -122.219723, 37.800244 ], [ -122.219588, 37.800408 ], [ -122.219402, 37.800695 ], [ -122.219364, 37.800746 ], [ -122.219273, 37.800841 ], [ -122.219205, 37.800899 ], [ -122.219104, 37.800961 ], [ -122.219035, 37.800992 ], [ -122.218944, 37.801023 ], [ -122.218859, 37.801047 ], [ -122.218742, 37.801044 ], [ -122.218701, 37.801037 ], [ -122.218562, 37.801001 ], [ -122.218226, 37.800916 ], [ -122.218073, 37.800877 ], [ -122.217303, 37.800688 ], [ -122.216727, 37.800536 ], [ -122.216632, 37.800514 ], [ -122.216521, 37.800479 ], [ -122.216313, 37.800394 ], [ -122.216227, 37.80037 ], [ -122.215996, 37.8003 ], [ -122.215724, 37.800225 ], [ -122.215035, 37.800098 ], [ -122.214891, 37.800071 ], [ -122.21406, 37.799861 ], [ -122.213436, 37.799696 ], [ -122.212984, 37.799583 ], [ -122.21283, 37.799541 ], [ -122.211748, 37.799273 ], [ -122.210794, 37.799023 ], [ -122.209852, 37.79879 ], [ -122.209283, 37.798631 ], [ -122.209056, 37.798576 ], [ -122.208863, 37.798545 ], [ -122.208779, 37.798538 ], [ -122.208731, 37.798541 ], [ -122.208672, 37.798545 ], [ -122.208518, 37.79857 ], [ -122.208043, 37.798671 ], [ -122.207923, 37.798683 ], [ -122.2078, 37.798687 ], [ -122.207748, 37.798678 ], [ -122.207694, 37.798666 ], [ -122.207662, 37.798656 ], [ -122.206815, 37.79828 ], [ -122.204938, 37.797417 ], [ -122.204794, 37.79735 ], [ -122.204689, 37.797276 ], [ -122.203297, 37.796152 ], [ -122.202272, 37.795321 ], [ -122.202092, 37.795175 ], [ -122.201184, 37.794394 ], [ -122.200662, 37.793846 ], [ -122.200575, 37.793754 ], [ -122.199968, 37.793085 ], [ -122.199396, 37.792457 ], [ -122.199237, 37.792285 ], [ -122.198812, 37.791812 ], [ -122.198225, 37.791159 ], [ -122.197907, 37.790802 ], [ -122.197727, 37.790602 ], [ -122.196857, 37.789636 ], [ -122.195843, 37.788532 ], [ -122.195334, 37.787976 ], [ -122.194808, 37.787387 ], [ -122.194769, 37.787322 ], [ -122.194596, 37.787144 ], [ -122.193967, 37.786585 ], [ -122.193871, 37.786492 ], [ -122.193303, 37.786005 ], [ -122.193225, 37.785948 ], [ -122.193103, 37.785874 ], [ -122.192945, 37.785798 ], [ -122.192825, 37.785747 ], [ -122.192724, 37.785709 ], [ -122.192564, 37.785662 ], [ -122.192424, 37.785631 ], [ -122.192119, 37.785577 ], [ -122.190954, 37.785379 ], [ -122.190621, 37.78532 ], [ -122.190332, 37.78526 ], [ -122.19002, 37.785174 ], [ -122.189776, 37.785104 ], [ -122.189044, 37.784855 ], [ -122.188693, 37.784724 ], [ -122.188513, 37.784678 ], [ -122.188428, 37.784659 ], [ -122.188333, 37.784625 ], [ -122.188217, 37.784591 ], [ -122.188077, 37.784571 ], [ -122.18762, 37.784553 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105089465116", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.142913, 37.738164 ], [ -122.14283, 37.738052 ], [ -122.142753, 37.738014 ], [ -122.142687, 37.73798 ], [ -122.142433, 37.737853 ], [ -122.142291, 37.73777 ], [ -122.142202, 37.737718 ], [ -122.142143, 37.73768 ], [ -122.142107, 37.737657 ], [ -122.14204, 37.737614 ], [ -122.142001, 37.73759 ], [ -122.141966, 37.737568 ], [ -122.141793, 37.737452 ], [ -122.141677, 37.737374 ], [ -122.141426, 37.737149 ], [ -122.141323, 37.737043 ], [ -122.141293, 37.737005 ], [ -122.141185, 37.736888 ], [ -122.141064, 37.736736 ], [ -122.141057, 37.736727 ], [ -122.14078, 37.736227 ], [ -122.140686, 37.736058 ], [ -122.140644, 37.735958 ], [ -122.140578, 37.735748 ], [ -122.140463, 37.735342 ], [ -122.140247, 37.734603 ], [ -122.140218, 37.734501 ], [ -122.140205, 37.734452 ], [ -122.140109, 37.734127 ], [ -122.140098, 37.734082 ], [ -122.139939, 37.733438 ], [ -122.13989, 37.733274 ], [ -122.139728, 37.732671 ], [ -122.139464, 37.731707 ], [ -122.139399, 37.731495 ], [ -122.139387, 37.731452 ], [ -122.139381, 37.731431 ], [ -122.139363, 37.731371 ], [ -122.139358, 37.731351 ], [ -122.139336, 37.731272 ], [ -122.13927, 37.731037 ], [ -122.139265, 37.73102 ], [ -122.13925, 37.730959 ], [ -122.139221, 37.73084 ], [ -122.139136, 37.730486 ], [ -122.139108, 37.730368 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105281275434", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.188796, 37.78382 ], [ -122.188521, 37.783766 ], [ -122.188413, 37.783761 ], [ -122.188364, 37.783766 ], [ -122.18828, 37.783783 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102638078801", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.229184, 37.801618 ], [ -122.228731, 37.801515 ], [ -122.228617, 37.80149 ], [ -122.22829, 37.801438 ], [ -122.227829, 37.801353 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102406970093", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.172133, 37.769131 ], [ -122.172029, 37.769094 ], [ -122.171334, 37.768625 ], [ -122.170849, 37.768297 ], [ -122.170673, 37.768172 ], [ -122.169999, 37.767714 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102406970094", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.139108, 37.730368 ], [ -122.139138, 37.730314 ], [ -122.138936, 37.729686 ], [ -122.138915, 37.729616 ], [ -122.138775, 37.729061 ], [ -122.138762, 37.728991 ], [ -122.138756, 37.728964 ], [ -122.138747, 37.728757 ], [ -122.13875, 37.728724 ], [ -122.138759, 37.728696 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102157509691", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.143408, 37.722274 ], [ -122.143379, 37.722206 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105281275687", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.188796, 37.78382 ], [ -122.188664, 37.783772 ], [ -122.188605, 37.783747 ], [ -122.18847, 37.783656 ], [ -122.188393, 37.783581 ], [ -122.18834, 37.783511 ], [ -122.188309, 37.783454 ], [ -122.188278, 37.783375 ], [ -122.188252, 37.783312 ], [ -122.188213, 37.783167 ], [ -122.188077, 37.782834 ], [ -122.188029, 37.782736 ], [ -122.188004, 37.782674 ], [ -122.187648, 37.781766 ], [ -122.187229, 37.780662 ], [ -122.187168, 37.780441 ], [ -122.187044, 37.779962 ], [ -122.187036, 37.779845 ], [ -122.187043, 37.779654 ], [ -122.187111, 37.77917 ], [ -122.187135, 37.778969 ], [ -122.187134, 37.778913 ], [ -122.18715, 37.77878 ], [ -122.187161, 37.778744 ], [ -122.187179, 37.77871 ], [ -122.187215, 37.778661 ], [ -122.187292, 37.778591 ], [ -122.187471, 37.778462 ], [ -122.187844, 37.778212 ], [ -122.187983, 37.778081 ], [ -122.188028, 37.778034 ], [ -122.188038, 37.778018 ], [ -122.188068, 37.777936 ], [ -122.188076, 37.777887 ], [ -122.188075, 37.77781 ], [ -122.18807, 37.777761 ], [ -122.188059, 37.777723 ], [ -122.188017, 37.777613 ], [ -122.187714, 37.77734 ], [ -122.187164, 37.776774 ], [ -122.186601, 37.776302 ], [ -122.185973, 37.775802 ], [ -122.185397, 37.775449 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105089436004", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.252363, 37.816305 ], [ -122.252307, 37.816155 ], [ -122.252002, 37.815347 ], [ -122.251449, 37.814183 ], [ -122.251259, 37.813747 ], [ -122.251233, 37.813677 ], [ -122.251191, 37.81348 ], [ -122.251086, 37.813083 ], [ -122.250936, 37.812551 ], [ -122.250753, 37.811873 ], [ -122.250698, 37.811713 ], [ -122.250636, 37.811559 ], [ -122.250597, 37.81148 ], [ -122.250486, 37.811315 ], [ -122.250413, 37.811222 ], [ -122.250393, 37.8112 ], [ -122.250358, 37.811161 ], [ -122.250333, 37.811139 ], [ -122.250312, 37.81112 ], [ -122.250277, 37.811088 ], [ -122.250173, 37.811013 ], [ -122.250144, 37.810993 ], [ -122.249683, 37.810684 ], [ -122.249618, 37.810644 ], [ -122.249438, 37.810536 ], [ -122.249351, 37.81047 ], [ -122.249107, 37.810315 ], [ -122.248922, 37.810219 ], [ -122.248829, 37.810178 ], [ -122.248682, 37.810118 ], [ -122.248235, 37.809967 ], [ -122.247462, 37.809748 ], [ -122.247338, 37.809709 ], [ -122.247106, 37.809635 ], [ -122.247018, 37.809596 ], [ -122.246958, 37.809562 ], [ -122.246832, 37.809514 ], [ -122.246673, 37.8094 ], [ -122.246453, 37.809328 ], [ -122.246256, 37.809234 ], [ -122.246, 37.809165 ], [ -122.245792, 37.809093 ], [ -122.245375, 37.808962 ], [ -122.245331, 37.808923 ], [ -122.244887, 37.808781 ], [ -122.244663, 37.808706 ], [ -122.243991, 37.808482 ], [ -122.243767, 37.808408 ], [ -122.242827, 37.808094 ], [ -122.242734, 37.808057 ], [ -122.242555, 37.807966 ], [ -122.242352, 37.807834 ], [ -122.242266, 37.80777 ], [ -122.242053, 37.807597 ], [ -122.241976, 37.807526 ], [ -122.241922, 37.807475 ], [ -122.241594, 37.807119 ], [ -122.241541, 37.807065 ], [ -122.241479, 37.80701 ], [ -122.241375, 37.806953 ], [ -122.241188, 37.806869 ], [ -122.2411, 37.806836 ], [ -122.241007, 37.806813 ], [ -122.240887, 37.806776 ], [ -122.240777, 37.806754 ], [ -122.240676, 37.806735 ], [ -122.240413, 37.806715 ], [ -122.240162, 37.806729 ], [ -122.24007, 37.806729 ], [ -122.239924, 37.80673 ], [ -122.239834, 37.806718 ], [ -122.239738, 37.806701 ], [ -122.239652, 37.806681 ], [ -122.239617, 37.806669 ], [ -122.239559, 37.806651 ], [ -122.239365, 37.806562 ], [ -122.239196, 37.806455 ], [ -122.239041, 37.806345 ], [ -122.239005, 37.80632 ], [ -122.238854, 37.806227 ], [ -122.238648, 37.8061 ], [ -122.238569, 37.806057 ], [ -122.238506, 37.806024 ], [ -122.238236, 37.805896 ], [ -122.237948, 37.805784 ], [ -122.237679, 37.805694 ], [ -122.23765, 37.805685 ], [ -122.237333, 37.805591 ], [ -122.23716, 37.805532 ], [ -122.236644, 37.805355 ], [ -122.236472, 37.805296 ], [ -122.236038, 37.805147 ], [ -122.236013, 37.805139 ], [ -122.235787, 37.805026 ], [ -122.235435, 37.804821 ], [ -122.235262, 37.804714 ], [ -122.23507, 37.804605 ], [ -122.234855, 37.804473 ], [ -122.234844, 37.804466 ], [ -122.234652, 37.804357 ], [ -122.234433, 37.804267 ], [ -122.234321, 37.804213 ], [ -122.234148, 37.80413 ], [ -122.233987, 37.804048 ], [ -122.233877, 37.803993 ], [ -122.233789, 37.803936 ], [ -122.233688, 37.803873 ], [ -122.233408, 37.803668 ], [ -122.233398, 37.803661 ], [ -122.232561, 37.803034 ], [ -122.232052, 37.802622 ], [ -122.231609, 37.802264 ], [ -122.230695, 37.80162 ], [ -122.230302, 37.801318 ], [ -122.230087, 37.801145 ], [ -122.229904, 37.801013 ], [ -122.229686, 37.800863 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105281275692", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.18828, 37.783783 ], [ -122.18819, 37.783476 ], [ -122.188155, 37.783354 ], [ -122.188108, 37.783212 ], [ -122.188061, 37.783064 ], [ -122.187984, 37.782821 ], [ -122.187935, 37.782683 ], [ -122.18791, 37.782625 ], [ -122.187849, 37.782484 ], [ -122.187779, 37.782317 ], [ -122.187704, 37.78212 ], [ -122.187287, 37.781024 ], [ -122.187148, 37.780659 ], [ -122.187, 37.780142 ], [ -122.186969, 37.780025 ], [ -122.186953, 37.77989 ], [ -122.186956, 37.779689 ], [ -122.18702, 37.779165 ], [ -122.187048, 37.77897 ], [ -122.18707, 37.778762 ], [ -122.187092, 37.778674 ], [ -122.187118, 37.778627 ], [ -122.187178, 37.778565 ], [ -122.187783, 37.77816 ], [ -122.187828, 37.778122 ], [ -122.187867, 37.778082 ], [ -122.187908, 37.778014 ], [ -122.187926, 37.777972 ], [ -122.187945, 37.777891 ], [ -122.187944, 37.777823 ], [ -122.187944, 37.777769 ], [ -122.187929, 37.777701 ], [ -122.187891, 37.777636 ], [ -122.187818, 37.777549 ], [ -122.187647, 37.777386 ], [ -122.187106, 37.776817 ], [ -122.186991, 37.776723 ], [ -122.186648, 37.776444 ], [ -122.186534, 37.776351 ], [ -122.185933, 37.775838 ], [ -122.185801, 37.775761 ], [ -122.185405, 37.77553 ], [ -122.185337, 37.775491 ], [ -122.18528, 37.775444 ], [ -122.185069, 37.775653 ], [ -122.184436, 37.776295 ], [ -122.184198, 37.776426 ], [ -122.184009, 37.776485 ], [ -122.183126, 37.775967 ], [ -122.182324, 37.775513 ], [ -122.181371, 37.774979 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105281275689", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.227829, 37.801353 ], [ -122.226914, 37.801134 ], [ -122.226326, 37.801027 ], [ -122.226042, 37.800972 ], [ -122.225883, 37.800948 ], [ -122.225826, 37.800938 ], [ -122.225625, 37.800905 ], [ -122.225182, 37.800823 ], [ -122.224968, 37.800784 ], [ -122.224748, 37.80074 ], [ -122.224089, 37.800611 ], [ -122.223941, 37.800582 ], [ -122.22387, 37.800568 ], [ -122.223651, 37.800527 ], [ -122.222996, 37.800404 ], [ -122.222778, 37.800364 ], [ -122.222373, 37.800292 ], [ -122.221159, 37.800076 ], [ -122.220755, 37.800005 ], [ -122.220657, 37.799981 ], [ -122.220363, 37.799934 ], [ -122.220262, 37.799925 ], [ -122.220153, 37.79993 ], [ -122.220078, 37.79994 ], [ -122.219996, 37.799963 ], [ -122.219938, 37.799985 ], [ -122.219863, 37.800025 ], [ -122.21979, 37.800078 ], [ -122.219646, 37.800206 ], [ -122.219609, 37.800248 ], [ -122.219379, 37.800573 ], [ -122.219324, 37.800659 ], [ -122.219285, 37.80071 ], [ -122.219192, 37.800808 ], [ -122.219117, 37.800865 ], [ -122.219055, 37.800896 ], [ -122.218994, 37.80092 ], [ -122.218947, 37.800937 ], [ -122.218846, 37.800959 ], [ -122.218794, 37.800966 ], [ -122.218727, 37.800965 ], [ -122.218654, 37.800958 ], [ -122.218575, 37.800942 ], [ -122.218248, 37.800859 ], [ -122.218069, 37.800814 ], [ -122.217498, 37.800674 ], [ -122.217311, 37.800629 ], [ -122.217226, 37.800609 ], [ -122.21709, 37.80057 ], [ -122.216739, 37.800471 ], [ -122.216436, 37.800369 ], [ -122.216291, 37.80032 ], [ -122.216221, 37.800294 ], [ -122.215695, 37.800148 ], [ -122.215055, 37.800036 ], [ -122.214117, 37.799805 ], [ -122.213733, 37.799703 ], [ -122.212989, 37.799517 ], [ -122.212849, 37.799488 ], [ -122.212634, 37.799434 ], [ -122.211989, 37.799275 ], [ -122.211774, 37.799222 ], [ -122.211575, 37.79917 ], [ -122.21098, 37.799014 ], [ -122.210782, 37.798963 ], [ -122.210605, 37.798918 ], [ -122.210077, 37.798786 ], [ -122.209901, 37.798742 ], [ -122.20974, 37.798705 ], [ -122.209679, 37.798689 ], [ -122.209299, 37.798589 ], [ -122.209019, 37.79851 ], [ -122.208986, 37.798501 ], [ -122.208794, 37.798478 ], [ -122.20872, 37.798476 ], [ -122.208653, 37.79848 ], [ -122.208578, 37.798489 ], [ -122.208498, 37.7985 ], [ -122.208027, 37.7986 ], [ -122.20794, 37.798612 ], [ -122.207879, 37.798617 ], [ -122.207828, 37.798618 ], [ -122.207755, 37.798611 ], [ -122.207725, 37.798603 ], [ -122.207175, 37.798357 ], [ -122.206805, 37.798192 ], [ -122.205529, 37.79761 ], [ -122.204982, 37.797361 ], [ -122.204842, 37.797293 ], [ -122.204795, 37.797263 ], [ -122.204641, 37.797136 ], [ -122.203688, 37.796356 ], [ -122.203371, 37.796096 ], [ -122.203174, 37.795938 ], [ -122.202583, 37.795466 ], [ -122.202387, 37.795309 ], [ -122.202159, 37.795127 ], [ -122.201503, 37.79454 ], [ -122.201285, 37.794345 ], [ -122.201157, 37.794219 ], [ -122.200775, 37.793843 ], [ -122.200735, 37.793803 ], [ -122.200653, 37.793713 ], [ -122.20053, 37.793578 ], [ -122.200163, 37.793176 ], [ -122.200041, 37.793042 ], [ -122.199927, 37.792916 ], [ -122.199585, 37.792538 ], [ -122.199472, 37.792413 ], [ -122.199441, 37.792376 ], [ -122.199349, 37.792266 ], [ -122.199319, 37.79223 ], [ -122.199233, 37.792137 ], [ -122.198978, 37.79186 ], [ -122.198893, 37.791768 ], [ -122.198775, 37.791638 ], [ -122.198421, 37.791248 ], [ -122.198304, 37.791118 ], [ -122.198234, 37.79104 ], [ -122.198025, 37.790809 ], [ -122.198007, 37.790789 ], [ -122.197954, 37.790734 ], [ -122.197923, 37.790699 ], [ -122.197831, 37.790594 ], [ -122.197801, 37.79056 ], [ -122.197625, 37.790367 ], [ -122.1971, 37.789788 ], [ -122.196925, 37.789595 ], [ -122.196723, 37.789374 ], [ -122.19612, 37.788713 ], [ -122.195919, 37.788493 ], [ -122.19571, 37.788246 ], [ -122.195144, 37.787614 ], [ -122.195062, 37.787524 ], [ -122.194896, 37.787343 ], [ -122.194846, 37.787285 ], [ -122.19433, 37.786793 ], [ -122.193913, 37.786459 ], [ -122.193905, 37.786452 ], [ -122.193456, 37.78606 ], [ -122.193312, 37.785949 ], [ -122.193242, 37.785901 ], [ -122.193066, 37.785801 ], [ -122.192882, 37.785716 ], [ -122.192685, 37.785645 ], [ -122.192631, 37.785629 ], [ -122.192596, 37.785619 ], [ -122.192371, 37.785567 ], [ -122.192132, 37.785524 ], [ -122.191669, 37.785442 ], [ -122.191657, 37.78544 ], [ -122.190565, 37.785249 ], [ -122.190463, 37.785228 ], [ -122.190285, 37.785179 ], [ -122.190175, 37.78515 ], [ -122.189833, 37.785053 ], [ -122.18944, 37.784924 ], [ -122.189275, 37.784866 ], [ -122.189162, 37.784814 ], [ -122.189078, 37.784769 ], [ -122.188892, 37.784678 ], [ -122.188766, 37.784606 ], [ -122.188649, 37.784522 ], [ -122.188586, 37.784446 ], [ -122.188536, 37.78435 ], [ -122.188477, 37.784239 ], [ -122.18844, 37.78414 ], [ -122.188429, 37.784109 ], [ -122.188358, 37.783916 ], [ -122.18828, 37.783783 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102954189105", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.161307, 37.755596 ], [ -122.16128, 37.755512 ], [ -122.160951, 37.754611 ], [ -122.160806, 37.754216 ], [ -122.16066, 37.75382 ], [ -122.160335, 37.752934 ], [ -122.159949, 37.751857 ], [ -122.159759, 37.751353 ], [ -122.159733, 37.751312 ], [ -122.159369, 37.750755 ], [ -122.15884, 37.749956 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1105281275688", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.194061, 37.786342 ], [ -122.194002, 37.786267 ], [ -122.193801, 37.786035 ], [ -122.193684, 37.785924 ], [ -122.193619, 37.785863 ], [ -122.193496, 37.785746 ], [ -122.193328, 37.785588 ], [ -122.193111, 37.785387 ], [ -122.192809, 37.785161 ], [ -122.192631, 37.785034 ], [ -122.192309, 37.784863 ], [ -122.191997, 37.784721 ], [ -122.191801, 37.784645 ], [ -122.191562, 37.784567 ], [ -122.19132, 37.7845 ], [ -122.190595, 37.784317 ], [ -122.190411, 37.784266 ], [ -122.189859, 37.784113 ], [ -122.189676, 37.784063 ], [ -122.18932, 37.783964 ], [ -122.188796, 37.78382 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102406970095", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.139108, 37.730368 ], [ -122.13905, 37.730332 ], [ -122.139022, 37.730245 ], [ -122.138876, 37.72979 ], [ -122.138851, 37.72971 ], [ -122.13883, 37.729638 ], [ -122.138686, 37.729074 ], [ -122.138673, 37.729004 ], [ -122.138664, 37.728927 ], [ -122.138656, 37.728819 ], [ -122.138658, 37.728729 ], [ -122.138664, 37.728702 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1104475134288", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.254277, 37.820339 ], [ -122.254332, 37.820577 ], [ -122.254499, 37.821292 ], [ -122.254529, 37.821417 ], [ -122.254566, 37.821528 ], [ -122.254635, 37.821679 ], [ -122.25465, 37.821711 ], [ -122.254732, 37.821838 ], [ -122.254838, 37.821967 ], [ -122.254938, 37.822071 ], [ -122.254946, 37.82208 ], [ -122.25506, 37.822185 ], [ -122.25518, 37.822268 ], [ -122.25554, 37.822519 ], [ -122.255578, 37.822545 ], [ -122.255661, 37.822603 ], [ -122.255733, 37.82265 ], [ -122.255949, 37.822792 ], [ -122.256022, 37.82284 ], [ -122.256144, 37.822927 ], [ -122.256513, 37.82319 ], [ -122.256577, 37.823235 ], [ -122.256601, 37.823265 ], [ -122.256617, 37.823296 ], [ -122.256663, 37.823366 ], [ -122.256758, 37.823436 ], [ -122.257247, 37.823798 ], [ -122.257335, 37.823864 ], [ -122.257409, 37.823921 ], [ -122.257653, 37.82406 ], [ -122.257796, 37.824142 ], [ -122.258083, 37.824297 ], [ -122.258392, 37.82442 ], [ -122.258412, 37.824427 ], [ -122.258566, 37.82448 ], [ -122.25868, 37.824515 ], [ -122.258898, 37.824585 ], [ -122.25926, 37.824703 ], [ -122.259557, 37.824787 ], [ -122.259778, 37.824851 ], [ -122.259934, 37.82489 ], [ -122.260404, 37.825007 ], [ -122.260561, 37.825047 ], [ -122.260773, 37.8251 ], [ -122.261055, 37.825172 ], [ -122.261414, 37.825253 ], [ -122.261629, 37.825302 ], [ -122.262478, 37.825485 ], [ -122.263584, 37.825753 ], [ -122.263788, 37.825815 ], [ -122.263933, 37.825865 ], [ -122.264029, 37.825898 ], [ -122.264426, 37.826074 ], [ -122.264934, 37.826321 ], [ -122.265154, 37.826428 ], [ -122.265267, 37.826478 ], [ -122.265509, 37.826579 ], [ -122.265562, 37.826595 ], [ -122.265877, 37.826694 ], [ -122.266298, 37.826793 ], [ -122.266486, 37.826823 ], [ -122.2668, 37.826875 ], [ -122.266882, 37.826887 ], [ -122.266978, 37.826901 ], [ -122.267129, 37.826922 ], [ -122.267211, 37.826936 ], [ -122.267521, 37.826995 ], [ -122.26755, 37.827001 ], [ -122.267828, 37.827044 ], [ -122.267946, 37.827062 ], [ -122.268142, 37.827093 ], [ -122.269047, 37.827232 ], [ -122.269147, 37.827246 ], [ -122.269581, 37.827312 ], [ -122.270429, 37.827441 ], [ -122.271186, 37.827552 ], [ -122.271637, 37.827619 ], [ -122.271722, 37.827629 ], [ -122.272305, 37.827724 ], [ -122.274056, 37.82801 ], [ -122.274558, 37.828093 ], [ -122.274641, 37.828104 ], [ -122.275406, 37.828205 ], [ -122.276124, 37.828334 ], [ -122.276561, 37.828391 ], [ -122.277117, 37.828471 ], [ -122.277969, 37.828569 ], [ -122.278366, 37.828592 ], [ -122.278619, 37.828606 ], [ -122.278796, 37.828608 ], [ -122.278951, 37.828606 ], [ -122.279057, 37.828601 ], [ -122.279188, 37.828597 ], [ -122.279246, 37.828598 ], [ -122.279323, 37.828595 ], [ -122.279659, 37.828586 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1104485773833", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.252807, 37.817194 ], [ -122.253124, 37.817686 ], [ -122.253265, 37.817878 ], [ -122.25341, 37.818041 ], [ -122.253868, 37.818603 ], [ -122.254027, 37.818743 ], [ -122.254131, 37.818873 ], [ -122.254186, 37.818964 ], [ -122.254197, 37.818981 ], [ -122.254212, 37.819013 ], [ -122.254242, 37.819077 ], [ -122.254263, 37.819183 ], [ -122.254337, 37.819515 ], [ -122.254361, 37.819713 ], [ -122.254409, 37.820056 ], [ -122.254434, 37.820324 ], [ -122.254727, 37.821437 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102156248968", "FULLNAME": "Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.23727, 37.805642 ], [ -122.236797, 37.805491 ], [ -122.236374, 37.805364 ], [ -122.23572, 37.805211 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1104485645649", "FULLNAME": "W Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.279659, 37.828586 ], [ -122.28029, 37.828515 ], [ -122.280422, 37.828496 ], [ -122.281495, 37.828243 ], [ -122.282427, 37.828023 ], [ -122.282504, 37.828013 ], [ -122.283334, 37.827904 ], [ -122.284137, 37.827741 ], [ -122.284224, 37.827722 ], [ -122.284373, 37.827686 ], [ -122.284454, 37.827668 ], [ -122.284507, 37.827673 ], [ -122.284562, 37.827708 ], [ -122.284639, 37.82781 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1104485605278", "FULLNAME": "W Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.279441, 37.828286 ], [ -122.279463, 37.828341 ], [ -122.279527, 37.828357 ], [ -122.279729, 37.82835 ], [ -122.280292, 37.82828 ], [ -122.280426, 37.828264 ], [ -122.28051, 37.828249 ], [ -122.281353, 37.828048 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1104475134436", "FULLNAME": "W Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.254277, 37.820339 ], [ -122.254332, 37.820577 ], [ -122.254499, 37.821292 ], [ -122.254529, 37.821417 ], [ -122.254566, 37.821528 ], [ -122.254635, 37.821679 ], [ -122.25465, 37.821711 ], [ -122.254732, 37.821838 ], [ -122.254838, 37.821967 ], [ -122.254938, 37.822071 ], [ -122.254946, 37.82208 ], [ -122.25506, 37.822185 ], [ -122.25518, 37.822268 ], [ -122.25554, 37.822519 ], [ -122.255578, 37.822545 ], [ -122.255661, 37.822603 ], [ -122.255733, 37.82265 ], [ -122.255949, 37.822792 ], [ -122.256022, 37.82284 ], [ -122.256144, 37.822927 ], [ -122.256513, 37.82319 ], [ -122.256577, 37.823235 ], [ -122.256601, 37.823265 ], [ -122.256617, 37.823296 ], [ -122.256663, 37.823366 ], [ -122.256758, 37.823436 ], [ -122.257247, 37.823798 ], [ -122.257335, 37.823864 ], [ -122.257409, 37.823921 ], [ -122.257653, 37.82406 ], [ -122.257796, 37.824142 ], [ -122.258083, 37.824297 ], [ -122.258392, 37.82442 ], [ -122.258412, 37.824427 ], [ -122.258566, 37.82448 ], [ -122.25868, 37.824515 ], [ -122.258898, 37.824585 ], [ -122.25926, 37.824703 ], [ -122.259557, 37.824787 ], [ -122.259778, 37.824851 ], [ -122.259934, 37.82489 ], [ -122.260404, 37.825007 ], [ -122.260561, 37.825047 ], [ -122.260773, 37.8251 ], [ -122.261055, 37.825172 ], [ -122.261414, 37.825253 ], [ -122.261629, 37.825302 ], [ -122.262478, 37.825485 ], [ -122.263584, 37.825753 ], [ -122.263788, 37.825815 ], [ -122.263933, 37.825865 ], [ -122.264029, 37.825898 ], [ -122.264426, 37.826074 ], [ -122.264934, 37.826321 ], [ -122.265154, 37.826428 ], [ -122.265267, 37.826478 ], [ -122.265509, 37.826579 ], [ -122.265562, 37.826595 ], [ -122.265877, 37.826694 ], [ -122.266298, 37.826793 ], [ -122.266486, 37.826823 ], [ -122.2668, 37.826875 ], [ -122.266882, 37.826887 ], [ -122.266978, 37.826901 ], [ -122.267129, 37.826922 ], [ -122.267211, 37.826936 ], [ -122.267521, 37.826995 ], [ -122.26755, 37.827001 ], [ -122.267828, 37.827044 ], [ -122.267946, 37.827062 ], [ -122.268142, 37.827093 ], [ -122.269047, 37.827232 ], [ -122.269147, 37.827246 ], [ -122.269581, 37.827312 ], [ -122.270429, 37.827441 ], [ -122.271186, 37.827552 ], [ -122.271637, 37.827619 ], [ -122.271722, 37.827629 ], [ -122.272305, 37.827724 ], [ -122.274056, 37.82801 ], [ -122.274558, 37.828093 ], [ -122.274641, 37.828104 ], [ -122.275406, 37.828205 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102407366406", "FULLNAME": "W Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.254409, 37.820056 ], [ -122.254434, 37.820324 ], [ -122.254727, 37.821437 ] ] } },
{ "type": "Feature", "properties": { "LINEARID": "1102156217102", "FULLNAME": "W Macarthur Blvd", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.279125, 37.828396 ], [ -122.27899, 37.828401 ], [ -122.278903, 37.828405 ], [ -122.278547, 37.828401 ], [ -122.278299, 37.828394 ], [ -122.278196, 37.828391 ], [ -122.277866, 37.828375 ], [ -122.277497, 37.82835 ], [ -122.277368, 37.828334 ], [ -122.277016, 37.828292 ], [ -122.276325, 37.828212 ], [ -122.275794, 37.828148 ], [ -122.275474, 37.828115 ], [ -122.275372, 37.828102 ], [ -122.274669, 37.828001 ], [ -122.274586, 37.827985 ], [ -122.271747, 37.827534 ] ] } },

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
#include <set>
#include <zlib.h>
#include <math.h>
#include <pthread.h>
#include "mvt.hpp"
#include "projection.hpp"
#include "pool.hpp"
@ -18,6 +19,9 @@
std::string dequote(std::string s);
bool pk = false;
size_t CPUS;
struct stats {
int minzoom;
int maxzoom;
@ -25,9 +29,8 @@ struct stats {
double minlat, minlon, maxlat, maxlon;
};
void handle(std::string message, int z, unsigned x, unsigned y, std::vector<std::set<type_and_string> > &file_keys, std::vector<std::string> &layernames, int *nlayers, sqlite3 *outdb, std::vector<std::string> &header, std::map<std::string, std::vector<std::string> > &mapping, std::set<std::string> &exclude, int ifmatched) {
void handle(std::string message, int z, unsigned x, unsigned y, std::map<std::string, layermap_entry> &layermap, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, std::set<std::string> &exclude, int ifmatched, mvt_tile &outtile) {
mvt_tile tile;
mvt_tile outtile;
int features_added = 0;
if (!tile.decode(message)) {
@ -37,26 +40,45 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::vector<std:
for (size_t l = 0; l < tile.layers.size(); l++) {
mvt_layer &layer = tile.layers[l];
mvt_layer outlayer;
outlayer.name = layer.name;
outlayer.version = layer.version;
outlayer.extent = layer.extent;
const char *ln = layer.name.c_str();
int ll;
for (ll = 0; ll < *nlayers; ll++) {
if (strcmp(layernames[ll].c_str(), ln) == 0) {
size_t ol;
for (ol = 0; ol < outtile.layers.size(); ol++) {
if (tile.layers[l].name == outtile.layers[ol].name) {
break;
}
}
if (ll == *nlayers) {
file_keys.push_back(std::set<type_and_string>());
layernames.push_back(std::string(ln));
*nlayers = ll + 1;
if (ol == outtile.layers.size()) {
outtile.layers.push_back(mvt_layer());
outtile.layers[ol].name = layer.name;
outtile.layers[ol].version = layer.version;
outtile.layers[ol].extent = layer.extent;
}
mvt_layer &outlayer = outtile.layers[ol];
if (layer.extent != outlayer.extent) {
if (layer.extent > outlayer.extent) {
for (size_t i = 0; i < outlayer.features.size(); i++) {
for (size_t j = 0; j < outlayer.features[i].geometry.size(); j++) {
outlayer.features[i].geometry[j].x = outlayer.features[i].geometry[j].x * layer.extent / outlayer.extent;
outlayer.features[i].geometry[j].y = outlayer.features[i].geometry[j].y * layer.extent / outlayer.extent;
}
}
outlayer.extent = layer.extent;
}
}
if (layermap.count(layer.name) == 0) {
layermap.insert(std::pair<std::string, layermap_entry>(layer.name, layermap_entry(layermap.size())));
auto file_keys = layermap.find(layer.name);
file_keys->second.minzoom = z;
file_keys->second.maxzoom = z;
}
auto file_keys = layermap.find(layer.name);
for (size_t f = 0; f < layer.features.size(); f++) {
mvt_feature feat = layer.features[f];
mvt_feature outfeature;
@ -106,12 +128,12 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::vector<std:
type_and_string tas;
tas.string = std::string(key);
tas.type = type;
file_keys[ll].insert(tas);
file_keys->second.file_keys.insert(tas);
outlayer.tag(outfeature, layer.keys[feat.tags[t]], val);
}
if (header.size() > 0 && strcmp(key, header[0].c_str()) == 0) {
std::map<std::string, std::vector<std::string> >::iterator ii = mapping.find(value);
std::map<std::string, std::vector<std::string>>::iterator ii = mapping.find(value);
if (ii != mapping.end()) {
std::vector<std::string> fields = ii->second;
@ -136,7 +158,7 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::vector<std:
type_and_string tas;
tas.string = std::string(sjoinkey);
tas.type = attr_type;
file_keys[ll].insert(tas);
file_keys->second.file_keys.insert(tas);
mvt_value outval;
if (attr_type == VT_STRING) {
@ -158,26 +180,29 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::vector<std:
outfeature.type = feat.type;
outfeature.geometry = feat.geometry;
if (layer.extent != outlayer.extent) {
for (size_t i = 0; i < outfeature.geometry.size(); i++) {
outfeature.geometry[i].x = outfeature.geometry[i].x * outlayer.extent / layer.extent;
outfeature.geometry[i].y = outfeature.geometry[i].y * outlayer.extent / layer.extent;
}
}
features_added++;
outlayer.features.push_back(outfeature);
if (z < file_keys->second.minzoom) {
file_keys->second.minzoom = z;
}
if (z > file_keys->second.maxzoom) {
file_keys->second.maxzoom = z;
}
}
}
outtile.layers.push_back(outlayer);
}
if (features_added == 0) {
return;
}
std::string compressed = outtile.encode();
if (compressed.size() > 500000) {
fprintf(stderr, "Tile %d/%u/%u size is %lld, >500000. Skipping this tile\n.", z, x, y, (long long) compressed.size());
return;
}
mbtiles_write_tile(outdb, z, x, y, compressed.data(), compressed.size());
}
double min(double a, double b) {
@ -196,7 +221,49 @@ double max(double a, double b) {
}
}
void decode(char *fname, char *map, std::vector<std::set<type_and_string> > &file_keys, std::vector<std::string> &layernames, int *nlayers, sqlite3 *outdb, struct stats *st, std::vector<std::string> &header, std::map<std::string, std::vector<std::string> > &mapping, std::set<std::string> &exclude, int ifmatched, std::string &attribution) {
struct reader {
long long zoom;
long long x;
long long sorty;
long long y;
std::string data;
sqlite3 *db;
sqlite3_stmt *stmt;
struct reader *next;
bool operator<(const struct reader &r) const {
if (zoom < r.zoom) {
return true;
}
if (zoom > r.zoom) {
return false;
}
if (x < r.x) {
return true;
}
if (x > r.x) {
return false;
}
if (sorty < r.sorty) {
return true;
}
if (sorty > r.sorty) {
return false;
}
if (data < r.data) {
return true;
}
return false;
}
};
struct reader *begin_reading(char *fname) {
sqlite3 *db;
if (sqlite3_open(fname, &db) != SQLITE_OK) {
@ -204,77 +271,274 @@ void decode(char *fname, char *map, std::vector<std::set<type_and_string> > &fil
exit(EXIT_FAILURE);
}
const char *sql = "SELECT zoom_level, tile_column, tile_row, tile_data from tiles;";
const char *sql = "SELECT zoom_level, tile_column, tile_row, tile_data from tiles order by zoom_level, tile_column, tile_row;";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
fprintf(stderr, "%s: select failed: %s\n", fname, sqlite3_errmsg(db));
exit(EXIT_FAILURE);
}
while (sqlite3_step(stmt) == SQLITE_ROW) {
long long zoom = sqlite3_column_int(stmt, 0);
long long x = sqlite3_column_int(stmt, 1);
long long y = sqlite3_column_int(stmt, 2);
y = (1LL << zoom) - 1 - y;
struct reader *r = new reader;
r->db = db;
r->stmt = stmt;
r->next = NULL;
int len = sqlite3_column_bytes(stmt, 3);
const char *s = (const char *) sqlite3_column_blob(stmt, 3);
if (sqlite3_step(stmt) == SQLITE_ROW) {
r->zoom = sqlite3_column_int(stmt, 0);
r->x = sqlite3_column_int(stmt, 1);
r->sorty = sqlite3_column_int(stmt, 2);
r->y = (1LL << r->zoom) - 1 - r->sorty;
fprintf(stderr, "%lld/%lld/%lld \r", zoom, x, y);
const char *data = (const char *) sqlite3_column_blob(stmt, 3);
size_t len = sqlite3_column_bytes(stmt, 3);
handle(std::string(s, len), zoom, x, y, file_keys, layernames, nlayers, outdb, header, mapping, exclude, ifmatched);
r->data = std::string(data, len);
} else {
r->zoom = 32;
}
sqlite3_finalize(stmt);
return r;
}
if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'minzoom'", -1, &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
int minzoom = sqlite3_column_int(stmt, 0);
st->minzoom = min(st->minzoom, minzoom);
struct zxy {
long long z;
long long x;
long long y;
zxy(long long _z, long long _x, long long _y) {
z = _z;
x = _x;
y = _y;
}
bool operator<(zxy const &other) const {
if (z < other.z) {
return true;
}
sqlite3_finalize(stmt);
}
if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'maxzoom'", -1, &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
int maxzoom = sqlite3_column_int(stmt, 0);
st->maxzoom = max(st->maxzoom, maxzoom);
if (z > other.z) {
return false;
}
sqlite3_finalize(stmt);
}
if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'center'", -1, &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
const unsigned char *s = sqlite3_column_text(stmt, 0);
sscanf((char *) s, "%lf,%lf", &st->midlon, &st->midlat);
if (x < other.x) {
return true;
}
sqlite3_finalize(stmt);
}
if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'attribution'", -1, &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
attribution = std::string((char *) sqlite3_column_text(stmt, 0));
if (x > other.x) {
return false;
}
sqlite3_finalize(stmt);
}
if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'bounds'", -1, &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
const unsigned char *s = sqlite3_column_text(stmt, 0);
double minlon, minlat, maxlon, maxlat;
sscanf((char *) s, "%lf,%lf,%lf,%lf", &minlon, &minlat, &maxlon, &maxlat);
st->minlon = min(minlon, st->minlon);
st->maxlon = max(maxlon, st->maxlon);
st->minlat = min(minlat, st->minlat);
st->maxlat = max(maxlat, st->maxlat);
if (y < other.y) {
return true;
}
return false;
}
};
struct arg {
std::map<zxy, std::vector<std::string>> inputs;
std::map<zxy, std::string> outputs;
std::map<std::string, layermap_entry> *layermap;
std::vector<std::string> *header;
std::map<std::string, std::vector<std::string>> *mapping;
std::set<std::string> *exclude;
int ifmatched;
};
void *join_worker(void *v) {
arg *a = (arg *) v;
for (auto ai = a->inputs.begin(); ai != a->inputs.end(); ++ai) {
mvt_tile tile;
for (size_t i = 0; i < ai->second.size(); i++) {
handle(ai->second[i], ai->first.z, ai->first.x, ai->first.y, *(a->layermap), *(a->header), *(a->mapping), *(a->exclude), a->ifmatched, tile);
}
ai->second.clear();
bool anything = false;
for (size_t i = 0; i < tile.layers.size(); i++) {
if (tile.layers[i].features.size() > 0) {
anything = true;
break;
}
}
if (anything) {
std::string compressed = tile.encode();
if (!pk && compressed.size() > 500000) {
fprintf(stderr, "Tile %lld/%lld/%lld size is %lld, >500000. Skipping this tile\n.", ai->first.z, ai->first.x, ai->first.y, (long long) compressed.size());
} else {
a->outputs.insert(std::pair<zxy, std::string>(ai->first, compressed));
}
}
sqlite3_finalize(stmt);
}
if (sqlite3_close(db) != SQLITE_OK) {
fprintf(stderr, "%s: could not close database: %s\n", fname, sqlite3_errmsg(db));
exit(EXIT_FAILURE);
return NULL;
}
void handle_tasks(std::map<zxy, std::vector<std::string>> &tasks, std::vector<std::map<std::string, layermap_entry>> &layermaps, sqlite3 *outdb, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, std::set<std::string> &exclude, int ifmatched) {
pthread_t pthreads[CPUS];
std::vector<arg> args;
for (size_t i = 0; i < CPUS; i++) {
args.push_back(arg());
args[i].layermap = &layermaps[i];
args[i].header = &header;
args[i].mapping = &mapping;
args[i].exclude = &exclude;
args[i].ifmatched = ifmatched;
}
size_t count = 0;
// This isn't careful about distributing tasks evenly across CPUs,
// but, from testing, it actually takes a little longer to do
// the proper allocation than is saved by perfectly balanced threads.
for (auto ai = tasks.begin(); ai != tasks.end(); ++ai) {
args[count].inputs.insert(*ai);
count = (count + 1) % CPUS;
if (ai == tasks.begin()) {
fprintf(stderr, "%lld/%lld/%lld \r", ai->first.z, ai->first.x, ai->first.y);
}
}
for (size_t i = 0; i < CPUS; i++) {
if (pthread_create(&pthreads[i], NULL, join_worker, &args[i]) != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
for (size_t i = 0; i < CPUS; i++) {
void *retval;
if (pthread_join(pthreads[i], &retval) != 0) {
perror("pthread_join");
}
for (auto ai = args[i].outputs.begin(); ai != args[i].outputs.end(); ++ai) {
mbtiles_write_tile(outdb, ai->first.z, ai->first.x, ai->first.y, ai->second.data(), ai->second.size());
}
}
}
void decode(struct reader *readers, char *map, std::map<std::string, layermap_entry> &layermap, sqlite3 *outdb, struct stats *st, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, std::set<std::string> &exclude, int ifmatched, std::string &attribution) {
std::vector<std::map<std::string, layermap_entry>> layermaps;
for (size_t i = 0; i < CPUS; i++) {
layermaps.push_back(std::map<std::string, layermap_entry>());
}
std::map<zxy, std::vector<std::string>> tasks;
while (readers != NULL && readers->zoom < 32) {
reader *r = readers;
readers = readers->next;
r->next = NULL;
zxy tile = zxy(r->zoom, r->x, r->y);
if (tasks.count(tile) == 0) {
tasks.insert(std::pair<zxy, std::vector<std::string>>(tile, std::vector<std::string>()));
}
auto f = tasks.find(tile);
f->second.push_back(r->data);
if (readers == NULL || readers->zoom != r->zoom || readers->x != r->x || readers->y != r->y) {
if (tasks.size() > 100 * CPUS) {
handle_tasks(tasks, layermaps, outdb, header, mapping, exclude, ifmatched);
tasks.clear();
}
}
if (sqlite3_step(r->stmt) == SQLITE_ROW) {
r->zoom = sqlite3_column_int(r->stmt, 0);
r->x = sqlite3_column_int(r->stmt, 1);
r->sorty = sqlite3_column_int(r->stmt, 2);
r->y = (1LL << r->zoom) - 1 - r->sorty;
const char *data = (const char *) sqlite3_column_blob(r->stmt, 3);
size_t len = sqlite3_column_bytes(r->stmt, 3);
r->data = std::string(data, len);
} else {
r->zoom = 32;
}
struct reader **rr;
for (rr = &readers; *rr != NULL; rr = &((*rr)->next)) {
if (*r < **rr) {
break;
}
}
r->next = *rr;
*rr = r;
}
handle_tasks(tasks, layermaps, outdb, header, mapping, exclude, ifmatched);
layermap = merge_layermaps(layermaps);
struct reader *next;
for (struct reader *r = readers; r != NULL; r = next) {
next = r->next;
sqlite3_finalize(r->stmt);
if (sqlite3_prepare_v2(r->db, "SELECT value from metadata where name = 'minzoom'", -1, &r->stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(r->stmt) == SQLITE_ROW) {
int minzoom = sqlite3_column_int(r->stmt, 0);
st->minzoom = min(st->minzoom, minzoom);
}
sqlite3_finalize(r->stmt);
}
if (sqlite3_prepare_v2(r->db, "SELECT value from metadata where name = 'maxzoom'", -1, &r->stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(r->stmt) == SQLITE_ROW) {
int maxzoom = sqlite3_column_int(r->stmt, 0);
st->maxzoom = max(st->maxzoom, maxzoom);
}
sqlite3_finalize(r->stmt);
}
if (sqlite3_prepare_v2(r->db, "SELECT value from metadata where name = 'center'", -1, &r->stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(r->stmt) == SQLITE_ROW) {
const unsigned char *s = sqlite3_column_text(r->stmt, 0);
sscanf((char *) s, "%lf,%lf", &st->midlon, &st->midlat);
}
sqlite3_finalize(r->stmt);
}
if (sqlite3_prepare_v2(r->db, "SELECT value from metadata where name = 'attribution'", -1, &r->stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(r->stmt) == SQLITE_ROW) {
attribution = std::string((char *) sqlite3_column_text(r->stmt, 0));
}
sqlite3_finalize(r->stmt);
}
if (sqlite3_prepare_v2(r->db, "SELECT value from metadata where name = 'bounds'", -1, &r->stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(r->stmt) == SQLITE_ROW) {
const unsigned char *s = sqlite3_column_text(r->stmt, 0);
double minlon, minlat, maxlon, maxlat;
sscanf((char *) s, "%lf,%lf,%lf,%lf", &minlon, &minlat, &maxlon, &maxlat);
st->minlon = min(minlon, st->minlon);
st->maxlon = max(maxlon, st->maxlon);
st->minlat = min(minlat, st->minlat);
st->maxlat = max(maxlat, st->maxlat);
}
sqlite3_finalize(r->stmt);
}
if (sqlite3_close(r->db) != SQLITE_OK) {
fprintf(stderr, "Could not close database: %s\n", sqlite3_errmsg(r->db));
exit(EXIT_FAILURE);
}
delete r;
}
}
void usage(char **argv) {
fprintf(stderr, "Usage: %s [-f] [-i] [-c joins.csv] [-x exclude ...] -o new.mbtiles source.mbtiles ...\n", argv[0]);
fprintf(stderr, "Usage: %s [-f] [-i] [-pk] [-c joins.csv] [-x exclude ...] -o new.mbtiles source.mbtiles ...\n", argv[0]);
exit(EXIT_FAILURE);
}
@ -322,7 +586,7 @@ std::string dequote(std::string s) {
return out;
}
void readcsv(char *fn, std::vector<std::string> &header, std::map<std::string, std::vector<std::string> > &mapping) {
void readcsv(char *fn, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping) {
FILE *f = fopen(fn, "r");
if (f == NULL) {
perror(fn);
@ -345,7 +609,7 @@ void readcsv(char *fn, std::vector<std::string> &header, std::map<std::string, s
for (size_t i = 0; i < line.size() && i < header.size(); i++) {
// printf("putting %s\n", line[0].c_str());
mapping.insert(std::pair<std::string, std::vector<std::string> >(line[0], line));
mapping.insert(std::pair<std::string, std::vector<std::string>>(line[0], line));
}
}
@ -358,8 +622,13 @@ int main(int argc, char **argv) {
int force = 0;
int ifmatched = 0;
CPUS = sysconf(_SC_NPROCESSORS_ONLN);
if (CPUS < 1) {
CPUS = 1;
}
std::vector<std::string> header;
std::map<std::string, std::vector<std::string> > mapping;
std::map<std::string, std::vector<std::string>> mapping;
std::set<std::string> exclude;
@ -367,7 +636,7 @@ int main(int argc, char **argv) {
extern char *optarg;
int i;
while ((i = getopt(argc, argv, "fo:c:x:i")) != -1) {
while ((i = getopt(argc, argv, "fo:c:x:ip:")) != -1) {
switch (i) {
case 'o':
outfile = optarg;
@ -381,6 +650,15 @@ int main(int argc, char **argv) {
ifmatched = 1;
break;
case 'p':
if (strcmp(optarg, "k") == 0) {
pk = true;
} else {
fprintf(stderr, "%s: Unknown option for -p%s\n", argv[0], optarg);
exit(EXIT_FAILURE);
}
break;
case 'c':
if (csv != NULL) {
fprintf(stderr, "Only one -c for now\n");
@ -414,20 +692,26 @@ int main(int argc, char **argv) {
st.minzoom = st.minlat = st.minlon = INT_MAX;
st.maxzoom = st.maxlat = st.maxlon = INT_MIN;
std::vector<std::set<type_and_string> > file_keys;
std::vector<std::string> layernames;
int nlayers = 0;
std::map<std::string, layermap_entry> layermap;
std::string attribution;
struct reader *readers = NULL;
for (i = optind; i < argc; i++) {
decode(argv[i], csv, file_keys, layernames, &nlayers, outdb, &st, header, mapping, exclude, ifmatched, attribution);
reader *r = begin_reading(argv[i]);
struct reader **rr;
for (rr = &readers; *rr != NULL; rr = &((*rr)->next)) {
if (*r < **rr) {
break;
}
}
r->next = *rr;
*rr = r;
}
std::map<std::string, layermap_entry> layermap;
for (i = 0; i < nlayers; i++) {
layermap.insert(std::pair<std::string, layermap_entry>(layernames[i], layermap_entry(layermap.size())));
layermap.find(layernames[i])->second.file_keys = file_keys[i];
}
decode(readers, csv, layermap, outdb, &st, header, mapping, exclude, ifmatched, attribution);
mbtiles_write_metadata(outdb, outfile, st.minzoom, st.maxzoom, st.minlat, st.minlon, st.maxlat, st.maxlon, st.midlat, st.midlon, 0, attribution.size() != 0 ? attribution.c_str() : NULL, layermap);
mbtiles_close(outdb, argv);

View File

@ -1 +1 @@
#define VERSION "tippecanoe v1.13.0\n"
#define VERSION "tippecanoe v1.14.0\n"