commit 017bf8fc1f929bcef3b9a5cfa2f69bc6f4356d33
parent cd5cc9a080461f9d0c3d58927d71906a6f2a8abf
Author: Tomas Hlavaty <tom@logand.com>
Date: Sun, 23 Jun 2019 21:36:06 +0200
interactive ui
Diffstat:
M | osmq | | | 35 | ++++++++++++++++++----------------- |
M | osmtile.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}