osmq

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

commit 017bf8fc1f929bcef3b9a5cfa2f69bc6f4356d33
parent cd5cc9a080461f9d0c3d58927d71906a6f2a8abf
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sun, 23 Jun 2019 21:36:06 +0200

interactive ui

Diffstat:
Mosmq | 35++++++++++++++++++-----------------
Mosmtile.c | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 274 insertions(+), 81 deletions(-)

diff --git a/osmq b/osmq @@ -1,19 +1,20 @@ -#!${bash}/bin/bash +#!/usr/bin/env bash set -e set -o pipefail -DIR=~/.cache/osmq -URL=$(curl \ - -s \ - "https://nominatim.openstreetmap.org/search?format=json&q=$*" \ - | jq \ - -r \ - 'map([.lat, .lon, .display_name] | join(", ")) | join("\n")' \ - | fzf -0 -1 --with-nth=3.. \ - | osmtile url $OSMQ_ZOOM) -CACHE=$(echo "$URL" | osmtile cache $DIR) -if test ! -f $CACHE; then - mkdir -p $(dirname "$CACHE") - curl -s "$URL" >"$CACHE" -fi -test -f $CACHE -fbi -a $CACHE +read \ + LAT \ + LON \ + REST \ + <<<$(curl \ + -s \ + "https://nominatim.openstreetmap.org/search?format=json&q=$*" \ + | jq \ + -r \ + 'map([.lat, .lon, .display_name] | join(" ")) | join("\n")' \ + | fzf -0 -1 --with-nth=3..) +osmtile \ + tty \ + "${OSMQ_CACHE:-$HOME/.cache/osmq}" \ + ${OSMQ_ZOOM:-10} \ + $LAT \ + $LON diff --git a/osmtile.c b/osmtile.c @@ -2,6 +2,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/wait.h> +#include <unistd.h> /* https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames */ static int long2tilex(double lon, int z) { @@ -21,7 +23,7 @@ static double tiley2lat(int y, int z) { return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n))); } -static int zoom(char *string) { +static int zoom_from_string(char *string) { int z; if(!string) goto fail; if(1 != sscanf(string, "%d", &z)) goto fail; @@ -33,7 +35,7 @@ static int zoom(char *string) { } static int lat(int argc, char *argv[]) { - int z = zoom(argv[0]); + int z = zoom_from_string(argv[0]); char *value = argv[1]; if(!value) goto fail; int y; @@ -46,7 +48,7 @@ static int lat(int argc, char *argv[]) { } static int lon(int argc, char *argv[]) { - int z = zoom(argv[0]); + int z = zoom_from_string(argv[0]); char *value = argv[1]; if(!value) goto fail; int x; @@ -58,86 +60,278 @@ static int lon(int argc, char *argv[]) { return 1; } +static double lon_from_string(char *string) { + if(!string) goto fail; + double z; + if(1 != sscanf(string, "%lf", &z)) goto fail; + return z; + fail: + fprintf(stderr, "unexpected longitude %s\n", string); + exit(1); +} + static int x(int argc, char *argv[]) { - int z = zoom(argv[0]); - char *value = argv[1]; - if(!value) goto fail; - double lon; - if(1 != sscanf(value, "%lf", &lon)) goto fail; + int z = zoom_from_string(argv[0]); + double lon = lon_from_string(argv[1]); printf("%d\n", long2tilex(lon, z)); return 0; +} + +static double lat_from_string(char *string) { + if(!string) goto fail; + double z; + if(1 != sscanf(string, "%lf", &z)) goto fail; + return z; fail: - fprintf(stderr, "unexpected longitude %s\n", value); - return 1; + fprintf(stderr, "unexpected latitude %s\n", string); + exit(1); } static int y(int argc, char *argv[]) { - int z = zoom(argv[0]); - char *value = argv[1]; - if(!value) goto fail; - double lat; - if(1 != sscanf(value, "%lf", &lat)) goto fail; + int z = zoom_from_string(argv[0]); + double lat = lat_from_string(argv[1]); printf("%d\n", lat2tiley(lat, z)); return 0; - fail: - fprintf(stderr, "unexpected latitude %s\n", value); - return 1; } -static int url(int argc, char *argv[]) { - int z = zoom(argv[0]); - double lat; - if(1 != scanf("%lf", &lat)) { - fprintf(stderr, "expected latitude\n"); +static int probe(char *path) { + FILE *f; + if((f = fopen(path, "r"))) { + fclose(f); return 1; } - char skip[1024]; - if(1 != scanf("%1023[ ,]", skip)) { - fprintf(stderr, "expected separator\n"); - return 1; - } - double lon; - if(1 != scanf("%lf", &lon)) { - fprintf(stderr, "expected longitude\n"); - return 1; - } - int x = long2tilex(lon, z); - int y = lat2tiley(lat, z); - printf("https://tile.openstreetmap.org/%d/%d/%d.png\n", z, x, y); return 0; } -static int cache(int argc, char *argv[]) { - char *dir = argv[0]; - if(!dir) goto fail; - for(int c = getchar(); c != ':'; c = getchar()) { - if(EOF == c) { - fprintf(stderr, "expected ':'\n"); - return 1; +static void run(char *args[]) { + int stat; + switch(fork()) { + case -1: + fprintf(stderr, "fork failed\n"); + exit(1); + case 0: + execvp(*args, args); + fprintf(stderr, "exec %s failed\n", *args); + exit(1); + default: + wait(&stat); + if(stat) { + fprintf(stderr, "%s failed %d\n", *args, stat); + exit(1); } } - for(int i = 0; i < 2; i++) { - if('/' != getchar()) { - fprintf(stderr, "expected '/'\n"); - return 1; - } +} + +static void cleanup(void) { + char *args1[] = {"tput", "cnorm", NULL}; + run(args1); + char *args2[] = {"stty", "-raw", "echo", NULL}; + run(args2); +} + +static void cached_file(int z, int x, int y, char *dir, char file[4096]) { + int max = (1 << z) - 1; + if(x < 0) x = max; + if(y < 0) y = max; + if(max < x) x = 0; + if(max < y) y = 0; + char d[4096]; + int n = snprintf(d, sizeof(d), "%s/%d/%d", dir, z, x); + if(n < 0 || sizeof(d) < n) { + fprintf(stderr, "directory path error\n"); + exit(1); + } + n = snprintf(file, 4096, "%s/%d.png", d, y); + if(n < 0 || 4096 < n) { + fprintf(stderr, "file path error\n"); + exit(1); } - for(int c = getchar(); c != '/'; c = getchar()) { - if(EOF == c) { - fprintf(stderr, "expected '/'\n"); - return 1; + if(!probe(file)) { + char url[4096]; + int n = snprintf(url, sizeof(url), "https://tile.openstreetmap.org/%d/%d/%d.png", z, x, y); + if(n < 0 || sizeof(url) < n) { + fprintf(stderr, "url error\n"); + exit(1); } + char *args1[] = {"mkdir", "-p", d, NULL}; + run(args1); + char *args2[] = {"curl", "-s", "-o", file, url, NULL}; + run(args2); + if(!probe(file)) { + fprintf(stderr, "cached file '%s' not found\n", file); + exit(1); + } + } +} + +static void screen_size(int *w, int *h) { + FILE *f = fopen("/sys/class/graphics/fb0/virtual_size", "r"); + if(!f) { + fprintf(stderr, "unknown screen\n"); + exit(1); + } + if(2 != fscanf(f, "%d,%d", w, h)) { + fprintf(stderr, "unknown screen size\n"); + exit(1); } - int z, x, y; - if(3 != scanf("%d/%d/%d.png", &z, &x, &y)) { - fprintf(stderr, "expected z/x/y.png\n"); + fclose(f); +} + +#define min(x, y) (x < y ? x : y) + +static int tty(int argc, char *argv[]) { + int width, height; + screen_size(&width, &height); + // popen r stty size -> w h + char *args0a[] = {"stty", "raw", "-echo", NULL}; + run(args0a); + char *args0b[] = {"tput", "civis", NULL}; + run(args0b); + atexit(cleanup); + char *dir = argv[0]; + if(!dir) { + fprintf(stderr, "unexpected dir %s\n", dir); return 1; } - printf("%s/%d/%d/%d.png\n", dir, z, x, y); - return 0; - fail: - fprintf(stderr, "unexpected dir %s\n", dir); - return 1; + int z0 = zoom_from_string(argv[1]); + double a0 = lat_from_string(argv[2]); + double o0 = lon_from_string(argv[3]); + int z = z0; + double a = a0, o = o0; + int x = long2tilex(o, z); + int y = lat2tiley(a, z); + unsigned char c; + for(;;) { + FILE *p = popen("w3mimgdisplay", "w"); + if(!p) { + fprintf(stderr, "popen w3mimgdisplay failed\n"); + exit(1); + } + for(int i = 0; i < 3; i++) { + for(int j = 0; j < 3; j++) { + char file[4096]; + cached_file(z, x + i - 1, y + j - 1, dir, file); + int w = min(width, height) / 3; + int h = w; + fprintf(p, "0;1;%d;%d;%d;%d;;;;;%s\n", w * i, h * j, w, h, file); + } + } + pclose(p); + if(1 != fread(&c, 1, 1, stdin)) return 0; + switch(c) { + case 27: /* esc */ + if(1 != fread(&c, 1, 1, stdin)) return 0; + switch(c) { + case '[': + if(1 != fread(&c, 1, 1, stdin)) return 0; + switch(c) { + case 'A': goto up; + case 'B': goto down; + case 'C': goto right; + case 'D': goto left; + } + break; + } + break; + case 'h': goto left; + case 'j': goto down; + case 'k': goto up; + case 'l': goto right; + case 'o': /* original position */ + a = a0; + o = o0; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '+': /* zoom in */ + z++; + if(18 < z) z = 18; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '-': /* zoom out */ + z--; + if(z < 0) z = 0; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '0': /* original zoom */ + z = z0; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case 'p': /* TODO print */ + break; + case '?': /* TODO help */ + break; + case 'q': /* quit */ + return 0; + case '1': + z = 2; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '2': + z = 4; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '3': + z = 6; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '4': + z = 8; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '5': + z = 10; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '6': + z = 12; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '7': + z = 14; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '8': + z = 16; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + case '9': + z = 18; + x = long2tilex(o, z); + y = lat2tiley(a, z); + break; + } + continue; + up: + if(0 < y) y--; + // TODO recompute a + continue; + down: + if(y < (1 << z) - 1) y++; + // TODO recompute a + continue; + right: + x++; + while((1 << z) - 1 < x) x -= (1 << z); + // TODO recompute o + continue; + left: + x--; + while(x < 0) x += (1 << z); + // TODO recompute o + continue; + } } static int version(int argc, char *argv[]) { @@ -153,8 +347,7 @@ static int help(int argc, char *argv[]) { printf(" lon zoom x\n"); printf(" x zoom longitude\n"); printf(" y zoom latitude\n"); - printf(" url zoom\n"); - printf(" cache dir\n"); + printf(" tty dir zoom lat lon\n"); printf(" --version\n"); printf(" --help\n"); return 0; @@ -171,8 +364,7 @@ int main(int argc, char *argv[]) { {"lon", lon}, {"x", x}, {"y", y}, - {"url", url}, - {"cache", cache}, + {"tty", tty}, {"--version", version}, {"--help", help}, {NULL}