int main(int argc, char **argv) { int i; extern int optind; extern char *optarg; char *destdir = NULL; int uniq = 0; while ((i = getopt(argc, argv, "o:u")) != -1) { switch (i) { case 'o': destdir = optarg; break; case 'u': uniq = 1; break; default: usage(argv); } } if (argc - optind < 1 || destdir == NULL) { usage(argv); } int nfile = argc - optind; int maxn = 0; int mapbits = 0; int metabits = 0; for (i = 0; i < nfile; i++) { char *fname = argv[optind + i]; char meta[strlen(fname) + 1 + 4 + 1]; sprintf(meta, "%s/meta", fname); FILE *f = fopen(meta, "r"); if (f == NULL) { perror(meta); exit(EXIT_FAILURE); } int file_mapbits, file_metabits, file_maxn; char s[2000] = ""; if (fgets(s, 2000, f) == NULL || strcmp(s, "1\n") != 0) { fprintf(stderr, "%s: Unknown version %s", meta, s); exit(EXIT_FAILURE); } if (fgets(s, 2000, f) == NULL || sscanf(s, "%d %d %d", &file_mapbits, &file_metabits, &file_maxn) != 3) { fprintf(stderr, "%s: couldn't find size declaration", meta); exit(EXIT_FAILURE); } fclose(f); if (i > 0) { if (file_mapbits != mapbits || file_metabits != metabits) { fprintf(stderr, "Mismatched encoding of %s (-z %d -m %d) and %s (-z %d -m %d)\n", argv[optind + i - 1], (mapbits - 16) / 2, metabits, argv[optind + i], (file_mapbits - 16) / 2, file_metabits); exit(EXIT_FAILURE); } } if (file_maxn > maxn) { maxn = file_maxn; } mapbits = file_mapbits; metabits = file_metabits; } int maxzoom = (mapbits - 16) / 2; if (mkdir(destdir, 0777) != 0) { perror(destdir); exit(EXIT_FAILURE); } char s[strlen(destdir) + 5 + 1]; sprintf(s, "%s/meta", destdir); FILE *f = fopen(s, "w"); if (f == NULL) { perror(s); exit(EXIT_FAILURE); } fprintf(f, "1\n"); fprintf(f, "%d %d %d\n", mapbits, metabits, maxn); fclose(f); int z_lookup; for (z_lookup = 0; z_lookup < maxzoom + 8; z_lookup++) { for (i = 1; i <= maxn; i++) { if (i == 1 && z_lookup != 0) { continue; } int bytes = bytesfor(mapbits, metabits, i, z_lookup); printf("merging zoom level %d for point count %d (%d bytes)\n", z_lookup, i, bytes); struct file files[nfile]; int n = 0; int remaining = 0; int j; for (j = 0; j < nfile; j++) { char *fname = argv[optind + j]; char fname2[strlen(fname) + 1 + 5 + 1 + 5 + 1]; sprintf(fname2, "%s/%d,%d", fname, i, z_lookup); files[n].fp = fopen(fname2, "rb"); if (files[n].fp == NULL) { perror(fname2); } else { files[n].data = malloc(bytes); files[n].remaining = fread(files[n].data, bytes, 1, files[n].fp); if (files[n].remaining > 0) { remaining++; } n++; } } if (remaining != 0) { char outfname[strlen(destdir) + 1 + 5 + 1 + 5 + 1]; sprintf(outfname, "%s/%d,%d", destdir, i, z_lookup); FILE *out = fopen(outfname, "wb"); if (out == NULL) { perror(outfname); exit(EXIT_FAILURE); } unsigned char wrote[bytes]; memset(wrote, 0, bytes); while (remaining) { int best = -1; for (j = 0; j < n; j++) { if (files[j].remaining) { if (best < 0 || memcmp(files[j].data, files[best].data, bytes) < 0) { best = j; } } } if (best < 0) { fprintf(stderr, "shouldn't happen\n"); break; } int skip = 0; if (uniq) { if (memcmp(wrote, files[best].data, bytes) == 0) { skip = 1; } memcpy(wrote, files[best].data, bytes); } if (!skip) { fwrite(files[best].data, bytes, 1, out); } files[best].remaining = fread(files[best].data, bytes, 1, files[best].fp); if (files[best].remaining <= 0) { remaining--; } } fclose(out); } for (j = 0; j < n; j++) { free(files[j].data); fclose(files[j].fp); } } } return 0; }
void read_file(FILE *f, char *destdir, struct file **files, int *maxn) { char s[MAX_INPUT]; double lat[MAX_INPUT], lon[MAX_INPUT]; int metasize[MAX_INPUT]; long long meta[MAX_INPUT]; unsigned int x[MAX_INPUT], y[MAX_INPUT]; unsigned long long seq = 0; while (fgets(s, MAX_INPUT, f)) { char *cp = s; int n = 0, m = 0; if (seq % 100000 == 0) { fprintf(stderr, "Read %.1f million records\r", seq / 1000000.0); } seq++; while (1) { if (sscanf(cp, "%lf,%lf", &lat[n], &lon[n]) == 2) { n++; while (*cp != '\0' && *cp != ' ') { cp++; } while (*cp == ' ') { cp++; } } else if (sscanf(cp, "%d:%lld", &metasize[m], &meta[m]) == 2) { m++; while (*cp != '\0' && *cp != ' ') { cp++; } while (*cp == ' ') { cp++; } } else { break; } } // Project each point to web mercator int i; for (i = 0; i < n; i++) { if (lat[i] > 85.0511 || lat[i] < -85.0511) { fprintf(stderr, "Can't represent latitude %f\n", lat[i]); n = 0; break; } if (lon[i] >= 180 || lon[i] <= -180) { fprintf(stderr, "Can't represent longitude %f\n", lon[i]); n = 0; break; } latlon2tile(lat[i], lon[i], 32, &x[i], &y[i]); } if (n == 0) { fprintf(stderr, "No valid points in %s", s); continue; } // If this is a polyline, find out how many leading bits in common // all the points have. int common = 0; if (n > 1) { int ok = 1; for (common = 0; ok && common < mapbits / 2; common++) { int x0 = x[0] & (1 << (31 - common)); int y0 = y[0] & (1 << (31 - common)); for (i = 1; i < n; i++) { if ((x[i] & (1 << (31 - common))) != x0 || (y[i] & (1 << (31 - common))) != y0) { ok = 0; break; } } if (!ok) { break; } } } if (n > *maxn) { *maxn = n; } int bytes = bytesfor(mapbits, metabits, n, common); unsigned char buf[bytes]; memset(buf, 0, bytes); int off = 0; xy2buf(x[0], y[0], buf, &off, mapbits, 0); for (i = 1; i < n; i++) { xy2buf(x[i], y[i], buf, &off, mapbits, common); } for (i = 0; i < m; i++) { meta2buf(metasize[i], meta[i], buf, &off, bytes * 8); } struct file **fo; for (fo = files; *fo != NULL; fo = &((*fo)->next)) { if ((*fo)->legs == n && (*fo)->level == common) { break; } } if (*fo == NULL) { *fo = malloc(sizeof(struct file)); if (*fo == NULL) { perror("malloc"); exit(EXIT_FAILURE); } char fn[strlen(destdir) + 10 + 1 + 10 + 1]; sprintf(fn, "%s/%d,%d", destdir, n, common); (*fo)->legs = n; (*fo)->level = common; (*fo)->f = fopen(fn, "w"); if ((*fo)->f == NULL) { perror(fn); exit(EXIT_FAILURE); } } fwrite(buf, sizeof(char), bytes, (*fo)->f); } }
int main(int argc, char **argv) { int i; extern int optind; extern char *optarg; char *destdir = NULL; while ((i = getopt(argc, argv, "z:m:o:")) != -1) { switch (i) { case 'z': mapbits = 2 * (atoi(optarg) + 8); break; case 'm': metabits = atoi(optarg); break; case 'o': destdir = optarg; break; default: usage(argv[0]); exit(EXIT_FAILURE); } } if (mapbits <= 8) { fprintf(stderr, "%s: Zoom level (-z) must be > 0\n", argv[0]); usage(argv[0]); exit(EXIT_FAILURE); } if (destdir == NULL) { fprintf(stderr, "%s: Must specify a directory with -o\n", argv[0]); usage(argv[0]); exit(EXIT_FAILURE); } if (mkdir(destdir, 0777) != 0) { perror(destdir); exit(EXIT_FAILURE); } struct file *files = NULL; int maxn = 0; if (optind == argc) { read_file(stdin, destdir, &files, &maxn); } else { for (i = optind; i < argc; i++) { FILE *f = fopen(argv[i], "r"); if (f == NULL) { perror(argv[i]); exit(EXIT_FAILURE); } read_file(f, destdir, &files, &maxn); fclose(f); } } char s[strlen(destdir) + 5 + 1]; sprintf(s, "%s/meta", destdir); FILE *f = fopen(s, "w"); if (f == NULL) { perror(s); exit(EXIT_FAILURE); } fprintf(f, "1\n"); fprintf(f, "%d %d %d\n", mapbits, metabits, maxn); fclose(f); for (; files != NULL; files = files->next) { fclose(files->f); char fn[strlen(destdir) + 10 + 1 + 10 + 1]; sprintf(fn, "%s/%d,%d", destdir, files->legs, files->level); int fd = open(fn, O_RDWR); if (fd < 0) { perror(fn); exit(EXIT_FAILURE); } struct stat st; if (fstat(fd, &st) < 0) { perror("stat"); exit(EXIT_FAILURE); } int bytes = bytesfor(mapbits, metabits, files->legs, files->level); gSortBytes = bytes; fprintf(stderr, "Sorting %lld shapes of %d point(s), zoom level %d\n", (long long) st.st_size / bytes, files->legs, files->level); int page = sysconf(_SC_PAGESIZE); long long unit = (50 * 1024 * 1024 / bytes) * bytes; while (unit % page != 0) { unit += bytes; } int nmerges = (st.st_size + unit - 1) / unit; struct merge merges[nmerges]; long long start; for (start = 0; start < st.st_size; start += unit) { long long end = start + unit; if (end > st.st_size) { end = st.st_size; } 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, fd, start); if (map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } qsort(map, (end - start) / bytes, bytes, bufcmp); // 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, fd, start); if (map2 == MAP_FAILED) { perror("mmap (write)"); exit(EXIT_FAILURE); } memcpy(map2, map, end - start); munmap(map, end - start); munmap(map2, end - start); } printf("\n"); void *map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } if (unlink(fn) != 0) { perror("unlink"); exit(EXIT_FAILURE); } FILE *f = fopen(fn, "w"); if (f == NULL) { perror(fn); exit(EXIT_FAILURE); } merge(merges, nmerges, map, f, bytes, st.st_size / bytes); munmap(map, st.st_size); fclose(f); close(fd); } fprintf(stderr, "\n"); return 0; }
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); } } } }
int main(int argc, char **argv) { int i; extern int optind; extern char *optarg; char *destdir = NULL; while ((i = getopt(argc, argv, "z:m:o:")) != -1) { switch (i) { case 'z': mapbits = 2 * (atoi(optarg) + 8); break; case 'm': metabits = atoi(optarg); break; case 'o': destdir = optarg; break; default: usage(argv[0]); exit(EXIT_FAILURE); } } if (mapbits <= 8) { fprintf(stderr, "%s: Zoom level (-z) must be > 0\n", argv[0]); usage(argv[0]); exit(EXIT_FAILURE); } if (destdir == NULL) { fprintf(stderr, "%s: Must specify a directory with -o\n", argv[0]); usage(argv[0]); exit(EXIT_FAILURE); } if (mkdir(destdir, 0777) != 0) { perror(destdir); exit(EXIT_FAILURE); } struct file *files = NULL; int maxn = 0; if (optind == argc) { read_file(stdin, destdir, &files, &maxn); } else { for (i = optind; i < argc; i++) { FILE *f = fopen(argv[i], "r"); if (f == NULL) { perror(argv[i]); exit(EXIT_FAILURE); } read_file(f, destdir, &files, &maxn); fclose(f); } } char s[strlen(destdir) + 5 + 1]; sprintf(s, "%s/meta", destdir); FILE *f = fopen(s, "w"); if (f == NULL) { perror(s); exit(EXIT_FAILURE); } fprintf(f, "1\n"); fprintf(f, "%d %d %d\n", mapbits, metabits, maxn); fclose(f); for (; files != NULL; files = files->next) { fclose(files->f); char fn[strlen(destdir) + 10 + 1 + 10 + 1]; sprintf(fn, "%s/%d,%d", destdir, files->legs, files->level); int fd = open(fn, O_RDONLY); if (fd < 0) { perror(fn); exit(EXIT_FAILURE); } struct stat st; if (fstat(fd, &st) < 0) { perror("stat"); exit(EXIT_FAILURE); } void *map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } int bytes = bytesfor(mapbits, metabits, files->legs, files->level); gSortBytes = bytes; fprintf(stderr, "Sorting %lld shapes of %d point(s), zoom level %d\n", (long long) st.st_size / bytes, files->legs, files->level); qsort(map, st.st_size / bytes, bytes, bufcmp); if (unlink(fn) != 0) { perror("unlink"); exit(EXIT_FAILURE); } int out = open(fn, O_RDWR | O_CREAT, 0666); if (out < 0) { perror(fn); exit(EXIT_FAILURE); } size_t off = 0; while (off < st.st_size) { ssize_t written = write(out, map + off, st.st_size - off); if (written < 0) { perror("write"); exit(1); } off += written; } munmap(map, st.st_size); close(fd); close(out); } return 0; }