osmq

openstreetmap for command line
git clone https://logand.com/git/osmq.git/
Log | Files | Refs

osmtile.c (8359B)


      1 #include <math.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <sys/wait.h>
      6 #include <unistd.h>
      7 
      8 #define fail(z, ...) ({fprintf(stderr, __VA_ARGS__); exit(z);})
      9 
     10 /* https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames */
     11 static int long2tilex(double lon, int z) {
     12   return (int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));
     13 }
     14 
     15 static int lat2tiley(double lat, int z) {
     16   return (int)(floor((1.0 - log(tan(lat * M_PI/180.0) + 1.0 / cos(lat * M_PI/180.0)) / M_PI) / 2.0 * pow(2.0, z)));
     17 }
     18 
     19 static double tilex2long(int x, int z) {
     20   return x / pow(2.0, z) * 360.0 - 180;
     21 }
     22 
     23 static double tiley2lat(int y, int z) {
     24   double n = M_PI - 2.0 * M_PI * y / pow(2.0, z);
     25   return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
     26 }
     27 
     28 static int zoom_from_string(char *string) {
     29   if(string) {
     30     int z;
     31     if(1 == sscanf(string, "%d", &z)) {
     32       if(0 <= z && z <= 18) {
     33         return z;
     34       }
     35     }
     36   }
     37   fail(1, "expected zoom 0 <= %s <= 18\n", string);
     38 }
     39 
     40 static int main_lat(int argc, char *argv[]) {
     41   int z = zoom_from_string(argv[0]);
     42   char *value = argv[1];
     43   if(value) {
     44     int y;
     45     if(1 == sscanf(value, "%d", &y)) {
     46       printf("%lf\n", tiley2lat(y, z));
     47       return 0;
     48     }
     49   }
     50   fail(1, "unexpected y %s\n", value);
     51 }
     52 
     53 static int main_lon(int argc, char *argv[]) {
     54   int z = zoom_from_string(argv[0]);
     55   char *value = argv[1];
     56   if(value) {
     57     int x;
     58     if(1 == sscanf(value, "%d", &x)) {
     59       printf("%lf\n", tilex2long(x, z));
     60       return 0;
     61     }
     62   }
     63   fail(1, "unexpected x %s\n", value);
     64 }
     65 
     66 static double lon_from_string(char *string) {
     67   if(string) {
     68     double z;
     69     if(1 == sscanf(string, "%lf", &z)) {
     70       return z;
     71     }
     72   }
     73   fail(1, "unexpected longitude %s\n", string);
     74 }
     75 
     76 static int main_x(int argc, char *argv[]) {
     77   int z = zoom_from_string(argv[0]);
     78   double lon = lon_from_string(argv[1]);
     79   printf("%d\n", long2tilex(lon, z));
     80   return 0;
     81 }
     82 
     83 static double lat_from_string(char *string) {
     84   if(string) {
     85     double z;
     86     if(1 == sscanf(string, "%lf", &z)) {
     87       return z;
     88     }
     89   }
     90   fail(1, "unexpected latitude %s\n", string);
     91 }
     92 
     93 static int main_y(int argc, char *argv[]) {
     94   int z = zoom_from_string(argv[0]);
     95   double lat = lat_from_string(argv[1]);
     96   printf("%d\n", lat2tiley(lat, z));
     97   return 0;
     98 }
     99 
    100 static int probe(char *path) {
    101   FILE *f;
    102   if((f = fopen(path, "r"))) {
    103     fclose(f);
    104     return 1;
    105   }
    106   return 0;
    107 }
    108 
    109 static int cached_file(int z, int x, int y, char *dir, char file[4096], int draw) {
    110   int max = (1 << z) - 1;
    111   if(x < 0) x = max;
    112   if(y < 0) y = max;
    113   if(max < x) x = 0;
    114   if(max < y) y = 0;
    115   char zxy[4096];
    116   int n = snprintf(zxy, sizeof(zxy), "%d/%d/%d", z, x, y);
    117   if(n < 0 || sizeof(zxy) < n) fail(1, "zxy error\n");
    118   n = snprintf(file, 4096, "%s/%s.png", dir, zxy);
    119   if(n < 0 || 4096 < n) fail(1, "file path error\n");
    120   if(probe(file)) return 1;
    121   if(draw) return 0;
    122   /* download tile in background */
    123   char *args[] = {"osmtile-download", zxy, dir, NULL};
    124   int pid = fork();
    125   if(pid < 0) fail(1, "fork failed\n");
    126   if(!pid) { /* child */
    127     execvp(*args, args);
    128     fail(1, "exec %s failed\n", *args);
    129   }
    130   return 0;
    131 }
    132 
    133 static void screen_size(int *w, int *h) {
    134   // TODO popen r stty size -> w h
    135   FILE *f = fopen("/sys/class/graphics/fb0/virtual_size", "r");
    136   if(!f) fail(1, "unknown screen\n");
    137   if(2 != fscanf(f, "%d,%d", w, h)) fail(1, "unknown screen size\n");
    138   fclose(f);
    139 }
    140 
    141 #define min(x, y) (x < y ? x : y)
    142 
    143 static unsigned char key(int timeout) {
    144   unsigned char c = 0; // timeout key by default
    145   if(timeout) {
    146     fd_set fds;
    147     FD_ZERO(&fds);
    148     FD_SET(0, &fds);
    149     struct timeval tv;
    150     tv.tv_sec = 1;
    151     tv.tv_usec = 0;
    152     int z = select(1, &fds, NULL, NULL, &tv);
    153     if(z < 0) {
    154       perror("select()");
    155       exit(1);
    156     } else if(z) {
    157       /* FD_ISSET(0, &fds) will be true. */
    158       if(1 != fread(&c, 1, 1, stdin)) exit(0);
    159     }
    160   } else {
    161     if(1 != fread(&c, 1, 1, stdin)) exit(0);
    162   }
    163   return c;
    164 }
    165 
    166 static int main_tty(int argc, char *argv[]) {
    167   int width, height;
    168   screen_size(&width, &height);
    169   char *dir = argv[0];
    170   if(!dir) fail(1, "unexpected dir %s\n", dir);
    171   int z0 = zoom_from_string(argv[1]);
    172   double a0 = lat_from_string(argv[2]);
    173   double o0 = lon_from_string(argv[3]);
    174   int z = z0;
    175   double a = a0, o = o0;
    176   int x = long2tilex(o, z);
    177   int y = lat2tiley(a, z);
    178   signal(SIGCHLD, SIG_IGN);
    179   for(;;) {
    180     FILE *p = popen("w3mimgdisplay", "w");
    181     if(!p) fail(1, "popen w3mimgdisplay failed\n");
    182     for(int i = 0; i < 3; i++) {
    183       for(int j = 0; j < 3; j++) {
    184         char file[4096];
    185         if(cached_file(z, x + i - 1, y + j - 1, dir, file, 1)) {
    186           int w = min(width, height) / 3;
    187           int h = w;
    188           fprintf(p, "0;1;%d;%d;%d;%d;;;;;%s\n", w * i, h * j, w, h, file);
    189         }
    190       }
    191     }
    192     pclose(p);
    193     for(int i = 0; i < 3; i++) {
    194       for(int j = 0; j < 3; j++) {
    195         char file[4096];
    196         cached_file(z, x + i - 1, y + j - 1, dir, file, 0);
    197       }
    198     }
    199     unsigned char c = key(1);
    200     switch(c) {
    201     case 27: /* esc */
    202       c = key(0);
    203       switch(c) {
    204       case '[':
    205         c = key(0);
    206         switch(c) {
    207         case 'A': goto up;
    208         case 'B': goto down;
    209         case 'C': goto right;
    210         case 'D': goto left;
    211         }
    212         break;
    213       }
    214       break;
    215     case 'h': goto left;
    216     case 'j': goto down;
    217     case 'k': goto up;
    218     case 'l': goto right;
    219     case 'o': /* original position */
    220       a = a0;
    221       o = o0;
    222       x = long2tilex(o, z);
    223       y = lat2tiley(a, z);
    224       break;
    225     case '+': /* zoom in */
    226       z++;
    227       if(18 < z) z = 18;
    228       x = long2tilex(o, z);
    229       y = lat2tiley(a, z);
    230       break;
    231     case '-': /* zoom out */
    232       z--;
    233       if(z < 0) z = 0;
    234       x = long2tilex(o, z);
    235       y = lat2tiley(a, z);
    236       break;
    237     case '0': /* original zoom */
    238       z = z0;
    239       x = long2tilex(o, z);
    240       y = lat2tiley(a, z);
    241       break;
    242     case 'p': /* TODO print */
    243       break;
    244     case '?': /* TODO help */
    245       break;
    246     case 'q': /* quit */
    247       return 0;
    248     case '1':
    249       z = 2;
    250       x = long2tilex(o, z);
    251       y = lat2tiley(a, z);
    252       break;
    253     case '2':
    254       z = 4;
    255       x = long2tilex(o, z);
    256       y = lat2tiley(a, z);
    257       break;
    258     case '3':
    259       z = 6;
    260       x = long2tilex(o, z);
    261       y = lat2tiley(a, z);
    262       break;
    263     case '4':
    264       z = 8;
    265       x = long2tilex(o, z);
    266       y = lat2tiley(a, z);
    267       break;
    268     case '5':
    269       z = 10;
    270       x = long2tilex(o, z);
    271       y = lat2tiley(a, z);
    272       break;
    273     case '6':
    274       z = 12;
    275       x = long2tilex(o, z);
    276       y = lat2tiley(a, z);
    277       break;
    278     case '7':
    279       z = 14;
    280       x = long2tilex(o, z);
    281       y = lat2tiley(a, z);
    282       break;
    283     case '8':
    284       z = 16;
    285       x = long2tilex(o, z);
    286       y = lat2tiley(a, z);
    287       break;
    288     case '9':
    289       z = 18;
    290       x = long2tilex(o, z);
    291       y = lat2tiley(a, z);
    292       break;
    293     }
    294     continue;
    295   up:
    296     if(0 < y) y--;
    297     // TODO recompute a
    298     continue;
    299   down:
    300     if(y < (1 << z) - 1) y++;
    301     // TODO recompute a
    302     continue;
    303   right:
    304     x++;
    305     while((1 << z) - 1 < x) x -= (1 << z);
    306     // TODO recompute o
    307     continue;
    308   left:
    309     x--;
    310     while(x < 0) x += (1 << z);
    311     // TODO recompute o
    312     continue;
    313   }
    314 }
    315 
    316 static int main_version(int argc, char *argv[]) {
    317   printf("%s\n",
    318 #include "VERSION"
    319          );
    320   return 0;
    321 }
    322 
    323 static int main_help(int argc, char *argv[]) {
    324   printf("usage: osmtile cmd args\n");
    325   printf("  lat zoom y\n");
    326   printf("  lon zoom x\n");
    327   printf("  x zoom longitude\n");
    328   printf("  y zoom latitude\n");
    329   printf("  tty dir zoom lat lon\n");
    330   printf("  --version\n");
    331   printf("  --help\n");
    332   return 0;
    333 }
    334 
    335 int main(int argc, char *argv[]) {
    336   char *cmd = argv[1];
    337   if(cmd) {
    338     static const struct {
    339       char *cmd;
    340       int (*fn)(int argc, char *argv[]);
    341     } dispatch[] = {
    342                     {"lat", main_lat},
    343                     {"lon", main_lon},
    344                     {"x", main_x},
    345                     {"y", main_y},
    346                     {"tty", main_tty},
    347                     {"--version", main_version},
    348                     {"--help", main_help},
    349                     {NULL}
    350     };
    351     for(int i = 0; dispatch[i].cmd; i++) {
    352       if(!strcmp(dispatch[i].cmd, cmd)) {
    353         return dispatch[i].fn(argc - 2, &argv[2]);
    354       }
    355     }
    356   }
    357   fail(1, "unexpected command %s\n", cmd);
    358 }