static double cloudsize(int z_draw, int x_draw, int y_draw) { double lat, lon; tile2latlon((x_draw + .5) * (1LL << (32 - z_draw)), (y_draw + .5) * (1LL << (32 - z_draw)), 32, &lat, &lon); double rat = cos(lat * M_PI / 180); double size = circle * .00000274; // in degrees size /= rat; // adjust for latitude size /= 360.0 / (1 << z_draw); // convert to tiles return size; }
void drawPixel(double x, double y, struct graphics *g, double bright, double hue, struct tilecontext *tc) { x -= tc->xoff; y -= tc->yoff; long long scale = 1LL << (32 - tc->z); long long bx = tc->x * scale; long long by = tc->y * scale; bx += x / g->width * scale; by += y / g->height * scale; double lat, lon; tile2latlon(bx, by, 32, &lat, &lon); printf("%.6f,%.6f\n", lat, lon); }
int read_json(int argc, char **argv, char *fname, const char *layername, int maxzoom, int minzoom, sqlite3 *outdb, struct pool *exclude, struct pool *include, int exclude_all, double droprate, int buffer, const char *tmpdir, double gamma, char *prevent) { int ret = EXIT_SUCCESS; char metaname[strlen(tmpdir) + strlen("/meta.XXXXXXXX") + 1]; char geomname[strlen(tmpdir) + strlen("/geom.XXXXXXXX") + 1]; char indexname[strlen(tmpdir) + strlen("/index.XXXXXXXX") + 1]; sprintf(metaname, "%s%s", tmpdir, "/meta.XXXXXXXX"); sprintf(geomname, "%s%s", tmpdir, "/geom.XXXXXXXX"); sprintf(indexname, "%s%s", tmpdir, "/index.XXXXXXXX"); int metafd = mkstemp(metaname); if (metafd < 0) { perror(metaname); exit(EXIT_FAILURE); } int geomfd = mkstemp(geomname); if (geomfd < 0) { perror(geomname); exit(EXIT_FAILURE); } int indexfd = mkstemp(indexname); if (indexfd < 0) { perror(indexname); exit(EXIT_FAILURE); } FILE *metafile = fopen(metaname, "wb"); if (metafile == NULL) { perror(metaname); exit(EXIT_FAILURE); } FILE *geomfile = fopen(geomname, "wb"); if (geomfile == NULL) { perror(geomname); exit(EXIT_FAILURE); } FILE *indexfile = fopen(indexname, "wb"); if (indexfile == NULL) { perror(indexname); exit(EXIT_FAILURE); } long long metapos = 0; long long geompos = 0; long long indexpos = 0; unlink(metaname); unlink(geomname); unlink(indexname); unsigned file_bbox[] = { UINT_MAX, UINT_MAX, 0, 0 }; unsigned midx = 0, midy = 0; long long seq = 0; int nlayers = argc; if (nlayers == 0) { nlayers = 1; } int n; for (n = 0; n < nlayers; n++) { json_pull *jp; const char *reading; FILE *fp; long long found_hashes = 0; long long found_features = 0; if (n >= argc) { reading = "standard input"; fp = stdin; } else { reading = argv[n]; fp = fopen(argv[n], "r"); if (fp == NULL) { perror(argv[n]); continue; } } jp = json_begin_file(fp); while (1) { json_object *j = json_read(jp); if (j == NULL) { if (jp->error != NULL) { fprintf(stderr, "%s:%d: %s\n", reading, jp->line, jp->error); } json_free(jp->root); break; } if (j->type == JSON_HASH) { found_hashes++; if (found_hashes == 50 && found_features == 0) { fprintf(stderr, "%s:%d: Not finding any GeoJSON features in input. Is your file just bare geometries?\n", reading, jp->line); break; } } json_object *type = json_hash_get(j, "type"); if (type == NULL || type->type != JSON_STRING || strcmp(type->string, "Feature") != 0) { continue; } found_features++; json_object *geometry = json_hash_get(j, "geometry"); if (geometry == NULL) { fprintf(stderr, "%s:%d: feature with no geometry\n", reading, jp->line); json_free(j); continue; } json_object *geometry_type = json_hash_get(geometry, "type"); if (geometry_type == NULL) { static int warned = 0; if (!warned) { fprintf(stderr, "%s:%d: null geometry (additional not reported)\n", reading, jp->line); warned = 1; } json_free(j); continue; } if (geometry_type->type != JSON_STRING) { fprintf(stderr, "%s:%d: geometry without type\n", reading, jp->line); json_free(j); continue; } json_object *properties = json_hash_get(j, "properties"); if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) { fprintf(stderr, "%s:%d: feature without properties hash\n", reading, jp->line); json_free(j); continue; } json_object *coordinates = json_hash_get(geometry, "coordinates"); if (coordinates == NULL || coordinates->type != JSON_ARRAY) { fprintf(stderr, "%s:%d: feature without coordinates array\n", reading, jp->line); json_free(j); continue; } int t; for (t = 0; t < GEOM_TYPES; t++) { if (strcmp(geometry_type->string, geometry_names[t]) == 0) { break; } } if (t >= GEOM_TYPES) { fprintf(stderr, "%s:%d: Can't handle geometry type %s\n", reading, jp->line, geometry_type->string); json_free(j); continue; } { unsigned bbox[] = { UINT_MAX, UINT_MAX, 0, 0 }; int nprop = 0; if (properties->type == JSON_HASH) { nprop = properties->length; } long long metastart = metapos; char *metakey[nprop]; char *metaval[nprop]; int metatype[nprop]; int m = 0; int i; for (i = 0; i < nprop; i++) { if (properties->keys[i]->type == JSON_STRING) { if (exclude_all) { if (!is_pooled(include, properties->keys[i]->string, VT_STRING)) { continue; } } else if (is_pooled(exclude, properties->keys[i]->string, VT_STRING)) { continue; } metakey[m] = properties->keys[i]->string; if (properties->values[i] != NULL && properties->values[i]->type == JSON_STRING) { metatype[m] = VT_STRING; metaval[m] = properties->values[i]->string; m++; } else if (properties->values[i] != NULL && properties->values[i]->type == JSON_NUMBER) { metatype[m] = VT_NUMBER; metaval[m] = properties->values[i]->string; m++; } else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_TRUE || properties->values[i]->type == JSON_FALSE)) { metatype[m] = VT_BOOLEAN; metaval[m] = properties->values[i]->type == JSON_TRUE ? "true" : "false"; m++; } else if (properties->values[i] != NULL && (properties->values[i]->type == JSON_NULL)) { ; } else { fprintf(stderr, "%s:%d: Unsupported property type for %s\n", reading, jp->line, properties->keys[i]->string); json_free(j); continue; } } } serialize_int(metafile, m, &metapos, fname); for (i = 0; i < m; i++) { serialize_int(metafile, metatype[i], &metapos, fname); serialize_string(metafile, metakey[i], &metapos, fname); serialize_string(metafile, metaval[i], &metapos, fname); } long long geomstart = geompos; serialize_byte(geomfile, mb_geometry[t], &geompos, fname); serialize_byte(geomfile, n, &geompos, fname); serialize_long_long(geomfile, metastart, &geompos, fname); parse_geometry(t, coordinates, bbox, &geompos, geomfile, VT_MOVETO, fname, jp); serialize_byte(geomfile, VT_END, &geompos, fname); /* * Note that minzoom for lines is the dimension * of the geometry in world coordinates, but * for points is the lowest zoom level (in tiles, * not in pixels) at which it should be drawn. * * So a line that is too small for, say, z8 * will have minzoom of 18 (if tile detail is 10), * not 8. */ int minzoom = 0; if (mb_geometry[t] == VT_LINE) { for (minzoom = 0; minzoom < 31; minzoom++) { unsigned mask = 1 << (32 - (minzoom + 1)); if (((bbox[0] & mask) != (bbox[2] & mask)) || ((bbox[1] & mask) != (bbox[3] & mask))) { break; } } } else if (mb_geometry[t] == VT_POINT) { double r = ((double) rand()) / RAND_MAX; if (r == 0) { r = .00000001; } minzoom = maxzoom - floor(log(r) / - log(droprate)); } serialize_byte(geomfile, minzoom, &geompos, fname); struct index index; index.start = geomstart; index.end = geompos; index.index = encode(bbox[0] / 2 + bbox[2] / 2, bbox[1] / 2 + bbox[3] / 2); fwrite_check(&index, sizeof(struct index), 1, indexfile, fname); indexpos += sizeof(struct index); for (i = 0; i < 2; i++) { if (bbox[i] < file_bbox[i]) { file_bbox[i] = bbox[i]; } } for (i = 2; i < 4; i++) { if (bbox[i] > file_bbox[i]) { file_bbox[i] = bbox[i]; } } if (seq % 10000 == 0) { fprintf(stderr, "Read %.2f million features\r", seq / 1000000.0); } seq++; } json_free(j); /* XXX check for any non-features in the outer object */ } json_end(jp); fclose(fp); } fclose(metafile); fclose(geomfile); fclose(indexfile); struct stat geomst; struct stat metast; if (fstat(geomfd, &geomst) != 0) { perror("stat geom\n"); exit(EXIT_FAILURE); } if (fstat(metafd, &metast) != 0) { perror("stat meta\n"); exit(EXIT_FAILURE); } if (geomst.st_size == 0 || metast.st_size == 0) { fprintf(stderr, "did not read any valid geometries\n"); exit(EXIT_FAILURE); } char *meta = (char *) mmap(NULL, metast.st_size, PROT_READ, MAP_PRIVATE, metafd, 0); if (meta == MAP_FAILED) { perror("mmap meta"); exit(EXIT_FAILURE); } struct pool file_keys1[nlayers]; struct pool *file_keys[nlayers]; int i; for (i = 0; i < nlayers; i++) { pool_init(&file_keys1[i], 0); file_keys[i] = &file_keys1[i]; } char *layernames[nlayers]; for (i = 0; i < nlayers; i++) { if (argc <= 1 && layername != NULL) { layernames[i] = strdup(layername); } else { char *src = argv[i]; if (argc < 1) { src = fname; } char *trunc = layernames[i] = malloc(strlen(src) + 1); const char *ocp, *use = src; for (ocp = src; *ocp; ocp++) { if (*ocp == '/' && ocp[1] != '\0') { use = ocp + 1; } } strcpy(trunc, use); char *cp = strstr(trunc, ".json"); if (cp != NULL) { *cp = '\0'; } cp = strstr(trunc, ".mbtiles"); if (cp != NULL) { *cp = '\0'; } layername = trunc; char *out = trunc; for (cp = trunc; *cp; cp++) { if (isalpha(*cp) || isdigit(*cp) || *cp == '_') { *out++ = *cp; } } *out = '\0'; printf("using layer %d name %s\n", i, trunc); } } /* Sort the index by geometry */ { int bytes = sizeof(struct index); fprintf(stderr, "Sorting %lld features\n", (long long) indexpos / bytes); int page = sysconf(_SC_PAGESIZE); long long unit = (50 * 1024 * 1024 / bytes) * bytes; while (unit % page != 0) { unit += bytes; } int nmerges = (indexpos + unit - 1) / unit; struct merge merges[nmerges]; long long start; for (start = 0; start < indexpos; start += unit) { long long end = start + unit; if (end > indexpos) { end = indexpos; } if (nmerges != 1) { fprintf(stderr, "Sorting part %lld of %d\r", start / unit + 1, nmerges); } merges[start / unit].start = start; merges[start / unit].end = end; merges[start / unit].next = NULL; void *map = mmap(NULL, end - start, PROT_READ | PROT_WRITE, MAP_PRIVATE, indexfd, start); if (map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } qsort(map, (end - start) / bytes, bytes, indexcmp); // Sorting and then copying avoids the need to // write out intermediate stages of the sort. void *map2 = mmap(NULL, end - start, PROT_READ | PROT_WRITE, MAP_SHARED, indexfd, start); if (map2 == MAP_FAILED) { perror("mmap (write)"); exit(EXIT_FAILURE); } memcpy(map2, map, end - start); munmap(map, end - start); munmap(map2, end - start); } if (nmerges != 1) { fprintf(stderr, "\n"); } void *map = mmap(NULL, indexpos, PROT_READ, MAP_PRIVATE, indexfd, 0); if (map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } FILE *f = fopen(indexname, "w"); if (f == NULL) { perror(indexname); exit(EXIT_FAILURE); } merge(merges, nmerges, (unsigned char *) map, f, bytes, indexpos / bytes); munmap(map, indexpos); fclose(f); close(indexfd); } /* Copy geometries to a new file in index order */ indexfd = open(indexname, O_RDONLY); if (indexfd < 0) { perror("reopen sorted index"); exit(EXIT_FAILURE); } struct index *index_map = mmap(NULL, indexpos, PROT_READ, MAP_PRIVATE, indexfd, 0); if (index_map == MAP_FAILED) { perror("mmap index"); exit(EXIT_FAILURE); } unlink(indexname); char *geom_map = mmap(NULL, geomst.st_size, PROT_READ, MAP_PRIVATE, geomfd, 0); if (geom_map == MAP_FAILED) { perror("mmap unsorted geometry"); exit(EXIT_FAILURE); } if (close(geomfd) != 0) { perror("close unsorted geometry"); } sprintf(geomname, "%s%s", tmpdir, "/geom.XXXXXXXX"); geomfd = mkstemp(geomname); if (geomfd < 0) { perror(geomname); exit(EXIT_FAILURE); } geomfile = fopen(geomname, "wb"); if (geomfile == NULL) { perror(geomname); exit(EXIT_FAILURE); } { geompos = 0; /* initial tile is 0/0/0 */ serialize_int(geomfile, 0, &geompos, fname); serialize_uint(geomfile, 0, &geompos, fname); serialize_uint(geomfile, 0, &geompos, fname); long long i; long long sum = 0; long long progress = 0; for (i = 0; i < indexpos / sizeof(struct index); i++) { fwrite_check(geom_map + index_map[i].start, sizeof(char), index_map[i].end - index_map[i].start, geomfile, fname); sum += index_map[i].end - index_map[i].start; long long p = 1000 * i / (indexpos / sizeof(struct index)); if (p != progress) { fprintf(stderr, "Reordering geometry: %3.1f%%\r", p / 10.0); progress = p; } } /* end of tile */ serialize_byte(geomfile, -2, &geompos, fname); fclose(geomfile); } if (munmap(index_map, indexpos) != 0) { perror("unmap sorted index"); } if (munmap(geom_map, geomst.st_size) != 0) { perror("unmap unsorted geometry"); } if (close(indexfd) != 0) { perror("close sorted index"); } /* Traverse and split the geometries for each zoom level */ geomfd = open(geomname, O_RDONLY); if (geomfd < 0) { perror("reopen sorted geometry"); exit(EXIT_FAILURE); } unlink(geomname); if (fstat(geomfd, &geomst) != 0) { perror("stat sorted geom\n"); exit(EXIT_FAILURE); } int fd[4]; off_t size[4]; fd[0] = geomfd; size[0] = geomst.st_size; int j; for (j = 1; j < 4; j++) { fd[j] = -1; size[j] = 0; } fprintf(stderr, "%lld features, %lld bytes of geometry, %lld bytes of metadata\n", seq, (long long) geomst.st_size, (long long) metast.st_size); int written = traverse_zooms(fd, size, meta, file_bbox, file_keys, &midx, &midy, layernames, maxzoom, minzoom, outdb, droprate, buffer, fname, tmpdir, gamma, nlayers, prevent); if (maxzoom != written) { fprintf(stderr, "\n\n\n*** NOTE TILES ONLY COMPLETE THROUGH ZOOM %d ***\n\n\n", written); maxzoom = written; ret = EXIT_FAILURE; } if (munmap(meta, metast.st_size) != 0) { perror("munmap meta"); } if (close(metafd) < 0) { perror("close meta"); } double minlat = 0, minlon = 0, maxlat = 0, maxlon = 0, midlat = 0, midlon = 0; tile2latlon(midx, midy, maxzoom, &maxlat, &minlon); tile2latlon(midx + 1, midy + 1, maxzoom, &minlat, &maxlon); midlat = (maxlat + minlat) / 2; midlon = (maxlon + minlon) / 2; tile2latlon(file_bbox[0], file_bbox[1], 32, &maxlat, &minlon); tile2latlon(file_bbox[2], file_bbox[3], 32, &minlat, &maxlon); if (midlat < minlat) { midlat = minlat; } if (midlat > maxlat) { midlat = maxlat; } if (midlon < minlon) { midlon = minlon; } if (midlon > maxlon) { midlon = maxlon; } mbtiles_write_metadata(outdb, fname, layernames, minzoom, maxzoom, minlat, minlon, maxlat, maxlon, midlat, midlon, file_keys, nlayers); // XXX layers for (i = 0; i < nlayers; i++) { pool_free_strings(&file_keys1[i]); free(layernames[i]); } return ret; }
void dump_out(int dump, unsigned int *x, unsigned int *y, int components, int metabits, long long meta) { if (dump == 2) { if (!first) { printf(","); } first = 0; printf("\n"); printf(" {\n"); printf(" \"type\": \"Feature\",\n"); printf(" \"properties\": {"); if (metabits != 0) { printf(" \"metadata\": %lld ", meta); } printf("},\n"); printf(" \"geometry\": {\n"); if (components == 1) { printf(" \"type\": \"Point\",\n"); } else { printf(" \"type\": \"LineString\",\n"); } printf(" \"coordinates\": [\n"); int k; for (k = 0; k < components; k++) { double lat, lon; tile2latlon(x[k], y[k], 32, &lat, &lon); printf(" "); if (components != 1) { printf("[ "); } printf("%lf, %lf", lon, lat); if (components != 1) { printf(" ]"); if (k + 1 < components) { printf(","); } } printf("\n"); } printf(" ]\n"); printf(" }\n"); printf(" }"); } else { int k; for (k = 0; k < components; k++) { double lat, lon; tile2latlon(x[k], y[k], 32, &lat, &lon); printf("%lf,%lf ", lat, lon); } if (metabits != 0) { printf("%d:%lld ", metabits, meta); } printf("// "); for (k = 0; k < components; k++) { printf("%08x %08x ", x[k], y[k]); } printf("\n"); } }
int process(char *fname, int components, int z_lookup, unsigned char *startbuf, unsigned char *endbuf, int z_draw, int x_draw, int y_draw, struct graphics *gc, int mapbits, int metabits, int dump, int gps, struct color_range *colors, int xoff, int yoff) { int bytes = bytesfor(mapbits, metabits, components, z_lookup); int ret = 0; char fn[strlen(fname) + 1 + 5 + 1 + 5 + 1]; struct tilecontext tc; tc.z = z_draw; tc.x = x_draw; tc.y = y_draw; tc.xoff = xoff; tc.yoff = yoff; if (components == 1) { sprintf(fn, "%s/1,0", fname); } else { sprintf(fn, "%s/%d,%d", fname, components, z_lookup); } int fd = open(fn, O_RDONLY); if (fd < 0) { // perror(fn); return ret; } struct stat st; if (fstat(fd, &st) < 0) { perror("stat"); exit(EXIT_FAILURE); } unsigned char *map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } gSortBytes = bytes; unsigned char *start = search(startbuf, map, st.st_size / bytes, bytes, bufcmp); unsigned char *end = search(endbuf, map, st.st_size / bytes, bytes, bufcmp); end += bytes; // points to the last value in range; need the one after that if (memcmp(start, startbuf, bytes) < 0) { start += bytes; // if not exact match, points to element before match } int step = 1; double brush = 1; double thick = line_thick; double bright1; if (components == 1) { bright1 = dot_bright; if (z_draw > dot_base) { step = 1; brush = exp(log(2.0) * (z_draw - dot_base)); bright1 *= exp(log(dot_ramp) * (z_draw - dot_base)); } else { step = floor(exp(log(exponent) * (dot_base - z_draw)) + .5); bright1 *= exp(log(dot_ramp) * (z_draw - dot_base)); bright1 = bright1 * step / (1 << (dot_base - z_draw)); } bright1 /= point_size; brush *= point_size; } else { bright1 = dot_bright * line_per_dot / line_thick; if (line_ramp >= 1) { thick *= exp(log(line_ramp) * (z_draw - dot_base)); bright1 *= exp(log(dot_ramp / line_ramp) * (z_draw - dot_base)); } else { bright1 *= exp(log(dot_ramp) * (z_draw - dot_base)); } } if (mercator >= 0) { double lat, lon; tile2latlon((x_draw + .5) * (1LL << (32 - z_draw)), (y_draw + .5) * (1LL << (32 - z_draw)), 32, &lat, &lon); double rat = cos(lat * M_PI / 180); double base = cos(mercator * M_PI / 180); brush /= rat * rat / (base * base); } if (dump) { step = 1; } else { // Align to step size so each zoom is a superset of the previous start = (start - map + (step * bytes - 1)) / (step * bytes) * (step * bytes) + map; } double size = cloudsize(z_draw, x_draw, y_draw); int innerstep = 1; long long todo = 0; size *= tilesize; // convert to pixels if (circle > 0) { // An additional 4 zoom levels without skipping // XXX Why 4? if (step > 1 && size > .0625) { innerstep = step; step = 1; } } const double b = brush * (tilesize / 256.0) * (tilesize / 256.0); for (; start < end; start += step * bytes) { unsigned int x[components], y[components]; double xd[components], yd[components]; int k; unsigned long long meta = 0; buf2xys(start, mapbits, metabits, z_lookup, components, x, y, &meta); if (meta > maxmeta) { continue; } if (!dump && z_draw >= mapbits / 2 - 8) { // Add noise below the bottom of the file resolution // so that it looks less gridded when overzoomed int j; for (j = 0; j < components; j++) { int noisebits = 32 - mapbits / 2; int i; for (i = 0; i < noisebits; i++) { x[j] |= ((y[j] >> (2 * noisebits - 1 - i)) & 1) << i; y[j] |= ((x[j] >> (2 * noisebits - 1 - i)) & 1) << i; } } } double hue = -1; if (metabits > 0 && colors->active) { hue = (((double) meta - colors->meta1) / (colors->meta2 - colors->meta1) * (colors->hue2 - colors->hue1) + colors->hue1) / 360; if (hue < -2) { hue = -1; } else { while (hue < 0) { hue++; } while (hue > 1) { hue--; } } } double bright = bright1; double bb = b; if (metabright) { bright *= meta; } if (metabrush) { bb = bb * meta; } for (k = 0; k < components; k++) { wxy2fxy(x[k], y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); } if (dump) { int should = 0; if (components == 1) { should = 1; } else { for (k = 1; k < components; k++) { double x1 = xd[k - 1]; double y1 = yd[k - 1]; double x2 = xd[k]; double y2 = yd[k]; if (clip(&x1, &y1, &x2, &y2, 0, 0, 1, 1)) { should = 1; break; } } } if (should) { dump_out(dump, x, y, components, metabits, meta); } } else if (components == 1) { if (!antialias) { xd[0] = ((int) (xd[0] * tilesize) + .5) / tilesize; yd[0] = ((int) (yd[0] * tilesize) + .5) / tilesize; } if (circle > 0) { if (size < .5) { if (bb <= 1) { drawPixel((xd[0] * tilesize - .5) + xoff, (yd[0] * tilesize - .5) + yoff, gc, bright * bb * meta / innerstep, hue, meta, &tc); } else { drawBrush((xd[0] * tilesize) + xoff, (yd[0] * tilesize) + yoff, gc, bright * meta / innerstep, bb, hue, meta, gaussian, &tc); ret = 1; } } else { double xc = (xd[0] * tilesize) + xoff; double yc = (yd[0] * tilesize) + yoff; if (xc + size >= 0 && yc + size >= 0 && xc - size <= tilesize && yc - size <= tilesize) { srand(x[0] * 37 + y[0]); for (todo += meta; todo > 0; todo -= innerstep) { double r = sqrt(((double) (rand() & (INT_MAX - 1))) / (INT_MAX)); double ang = ((double) (rand() & (INT_MAX - 1))) / (INT_MAX) * 2 * M_PI; double xp = xc + size * r * cos(ang); double yp = yc + size * r * sin(ang); if (bb <= 1) { drawPixel(xp - .5, yp - .5, gc, bright * bb, hue, meta, &tc); } else { drawBrush(xp, yp, gc, bright, bb, hue, meta, gaussian, &tc); ret = 1; } } } } } else { if (bb <= 1) { drawPixel((xd[0] * tilesize - .5) + xoff, (yd[0] * tilesize - .5) + yoff, gc, bright * bb, hue, meta, &tc); } else { drawBrush((xd[0] * tilesize) + xoff, (yd[0] * tilesize) + yoff, gc, bright, bb, hue, meta, gaussian, &tc); ret = 1; } } } else { for (k = 1; k < components; k++) { double bright1 = bright; long long xk1 = x[k - 1]; long long xk = x[k]; if (gps) { double xdist = (long long) x[k] - (long long) x[k - 1]; double ydist = (long long) y[k] - (long long) y[k - 1]; double dist = sqrt(xdist * xdist + ydist * ydist); double min = gps_dist; min = min * exp(log(gps_ramp) * (gps_base - z_draw)); if (dist > min) { bright1 /= (dist / min); } if (bright1 < .0025) { continue; } } double thick1 = thick * tilesize / 256.0; if (xk - xk1 >= (1LL << 31)) { wxy2fxy(xk - (1LL << 32), y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); drawClip(xd[k - 1] * tilesize + xoff, yd[k - 1] * tilesize + yoff, xd[k] * tilesize + xoff, yd[k] * tilesize + yoff, gc, bright1, hue, meta, antialias, thick1, &tc); wxy2fxy(x[k], y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); wxy2fxy(xk1 + (1LL << 32), y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); drawClip(xd[k - 1] * tilesize + xoff, yd[k - 1] * tilesize + yoff, xd[k] * tilesize + xoff, yd[k] * tilesize + yoff, gc, bright1, hue, meta, antialias, thick1, &tc); wxy2fxy(x[k - 1], y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); } else if (xk1 - xk >= (1LL << 31)) { wxy2fxy(xk1 - (1LL << 32), y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); drawClip(xd[k - 1] * tilesize + xoff, yd[k - 1] * tilesize + yoff, xd[k] * tilesize + xoff, yd[k] * tilesize + yoff, gc, bright1, hue, meta, antialias, thick1, &tc); wxy2fxy(x[k - 1], y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); wxy2fxy(xk + (1LL << 32), y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); drawClip(xd[k - 1] * tilesize + xoff, yd[k - 1] * tilesize + yoff, xd[k] * tilesize + xoff, yd[k] * tilesize + yoff, gc, bright1, hue, meta, antialias, thick1, &tc); wxy2fxy(x[k], y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); } else { drawClip(xd[k - 1] * tilesize + xoff, yd[k - 1] * tilesize + yoff, xd[k] * tilesize + xoff, yd[k] * tilesize + yoff, gc, bright1, hue, meta, antialias, thick1, &tc); } } } }
int process(char *fname, int components, int z_lookup, unsigned char *startbuf, unsigned char *endbuf, int z_draw, int x_draw, int y_draw, double *image, double *cx, double *cy, int mapbits, int metabits, int dump, int gps, int colors) { int bytes = bytesfor(mapbits, metabits, components, z_lookup); int ret = 0; char fn[strlen(fname) + 1 + 5 + 1 + 5 + 1]; if (components == 1) { sprintf(fn, "%s/1,0", fname); } else { sprintf(fn, "%s/%d,%d", fname, components, z_lookup); } int fd = open(fn, O_RDONLY); if (fd < 0) { perror(fn); return ret; } struct stat st; if (fstat(fd, &st) < 0) { perror("stat"); exit(EXIT_FAILURE); } unsigned char *map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } gSortBytes = bytes; unsigned char *start = search(startbuf, map, st.st_size / bytes, bytes, bufcmp); unsigned char *end = search(endbuf, map, st.st_size / bytes, bytes, bufcmp); end += bytes; // points to the last value in range; need the one after that if (memcmp(start, startbuf, bytes) < 0) { start += bytes; // if not exact match, points to element before match } int step = 1; double brush = 1; double bright1; if (components == 1) { bright1 = dot_bright; if (z_draw > dot_base) { step = 1; brush = 1 << (multiplier * (z_draw - dot_base)); } else { step = 1 << (multiplier * (dot_base - z_draw)); } bright1 *= exp(log(dot_ramp) * (z_draw - dot_base)); } else { bright1 = dot_bright * line_per_dot; bright1 *= exp(log(dot_ramp) * (z_draw - dot_base)); } if (dump) { step = 1; } else { // Align to step size so each zoom is a superset of the previous start = (start - map) / (step * bytes) * (step * bytes) + map; } for (; start < end; start += step * bytes) { unsigned int x[components], y[components]; double xd[components], yd[components]; int k; unsigned int meta = 0; buf2xys(start, mapbits, metabits, z_lookup, components, x, y, &meta); if (!dump && z_draw >= mapbits / 2 - 8) { // Add noise below the bottom of the file resolution // so that it looks less gridded when overzoomed int j; for (j = 0; j < components; j++) { int noisebits = 32 - mapbits / 2; int i; for (i = 0; i < noisebits; i++) { x[j] |= ((y[j] >> (2 * noisebits - 1 - i)) & 1) << i; y[j] |= ((x[j] >> (2 * noisebits - 1 - i)) & 1) << i; } } } double hue = -1; if (metabits > 0 && colors > 0) { hue = (double) meta / colors; } double bright = bright1; if (mercator >= 0) { double lat, lon; tile2latlon(x[0], y[0], 32, &lat, &lon); double rat = cos(lat * M_PI / 180); double base = cos(mercator * M_PI / 180); bright /= rat * rat / (base * base); } for (k = 0; k < components; k++) { wxy2fxy(x[k], y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); } if (dump) { int should = 0; if (components == 1) { should = 1; } else { for (k = 1; k < components; k++) { if (drawClip(xd[k - 1], yd[k - 1], xd[k], yd[k], NULL, NULL, NULL, 0, 0, 0)) { should = 1; break; } } } if (should) { for (k = 0; k < components; k++) { double lat, lon; tile2latlon(x[k], y[k], 32, &lat, &lon); printf("%lf,%lf ", lat, lon); } if (metabits != 0) { printf("%d:%d ", metabits, meta); } printf("// "); for (k = 0; k < components; k++) { printf("%08x %08x ", x[k], y[k]); } printf("\n"); } } else if (components == 1) { if (!antialias) { xd[0] = (int) xd[0] + .5; yd[0] = (int) yd[0] + .5; } if (brush <= 1) { drawPixel(xd[0] - .5, yd[0] - .5, image, cx, cy, bright * brush, hue); } else { drawBrush(xd[0], yd[0], image, cx, cy, bright, brush, hue); ret = 1; } } else { for (k = 1; k < components; k++) { double bright1 = bright; long long xk1 = x[k - 1]; long long xk = x[k]; if (gps) { double xdist = (long long) x[k] - (long long) x[k - 1]; double ydist = (long long) y[k] - (long long) y[k - 1]; double dist = sqrt(xdist * xdist + ydist * ydist); double min = gps_dist; min = min * exp(log(gps_ramp) * (gps_base - z_draw)); if (dist > min) { bright1 /= (dist / min); } if (bright1 < .0025) { continue; } } if (xk - xk1 >= (1LL << 31)) { wxy2fxy(xk - (1LL << 32), y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); drawClip(xd[k - 1], yd[k - 1], xd[k], yd[k], image, cx, cy, bright1, hue, antialias); wxy2fxy(x[k], y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); wxy2fxy(xk1 + (1LL << 32), y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); drawClip(xd[k - 1], yd[k - 1], xd[k], yd[k], image, cx, cy, bright1, hue, antialias); wxy2fxy(x[k - 1], y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); } else if (xk1 - xk >= (1LL << 31)) { wxy2fxy(xk1 - (1LL << 32), y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); drawClip(xd[k - 1], yd[k - 1], xd[k], yd[k], image, cx, cy, bright1, hue, antialias); wxy2fxy(x[k - 1], y[k - 1], &xd[k - 1], &yd[k - 1], z_draw, x_draw, y_draw); wxy2fxy(xk + (1LL << 32), y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); drawClip(xd[k - 1], yd[k - 1], xd[k], yd[k], image, cx, cy, bright1, hue, antialias); wxy2fxy(x[k], y[k], &xd[k], &yd[k], z_draw, x_draw, y_draw); } else { drawClip(xd[k - 1], yd[k - 1], xd[k], yd[k], image, cx, cy, bright1, hue, antialias); } } } }