ref: 726126c176ac091ac28a14ae5efcded255dac71b
dir: /map.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <keyboard.h>
#include <nate/nate.h>
#include <nate/n_window.h>
#include <nate/n_hbox.h>
#include <nate/n_vbox.h>
#include <nate/n_box.h>
#include <nate/n_label.h>
#include <nate/n_button.h>
#include <nate/n_image.h>
#include "dat.h"
#include "fns.h"
void
debugprint(char *fmt, ...)
{
va_list args;
if (!debug)
return;
va_start(args, fmt);
vfprint(2, fmt, args);
va_end(args);
}
static void
runchecks(void)
{
if (access("/mnt/map/0", AEXIST) < 0)
sysfatal("/mnt/map does not exist: %r");
}
GPos gpsloc;
GBundle currentloc;
Point drawoffset;
int maxzoom = 8;
int zoom = 5;
int tilesize = 256;
Point mapimagesize;
Image *mapimage;
QLock mapimagelock;
char statusline[512];
static char*
getstatusline(void)
{
char ns;
char we;
ns = gpsloc.lat > 90 ? 'N' : 'S';
we = gpsloc.lon > 360 ? 'W' : 'E';
snprint(statusline, sizeof statusline, "Loc: %f %c %f %c Z: %d",
gpsloc.lon - 180, we,
gpsloc.lat - 90, ns,
currentloc.z);
return statusline;
}
ulong *zoomsquared;
static void
initmapfs(void)
{
int fd, n;
char buf[32];
fd = open("/mnt/map/ctl", OREAD);
if (fd < 0)
sysfatal("mapfs error: open ctl: %r");
n = read(fd, buf, sizeof(buf) - 1);
if (n < 0)
sysfatal("mapfs error: read ctl: %r");
close(fd);
buf[n] = 0;
maxzoom = atoi(buf);
zoomsquared = mallocz(sizeof(ulong) * (maxzoom+1), 1);
for (int i = 0; i <= maxzoom; i++) {
zoomsquared[i] = 1;
for (int j = 0; j <= i; j++)
zoomsquared[i] *= 2;
}
}
static double
gettiledeg(void)
{
return 360 / zoomsquared[currentloc.z];
}
NWindow *mainwindow;
NImage *nimage;
enum {
Cnil,
Credraw,
};
void
lockmapimage(void)
{
qlock(&mapimagelock);
}
void
unlockmapimage(void)
{
qunlock(&mapimagelock);
}
static GPos
gpsoff(void)
{
GPos p;
Point off;
double x, y;
if (gpsloc.lat > 180)
gpsloc.lat = 180;
if (gpsloc.lat < 0)
gpsloc.lat = 0;
off = divpt(mapimagesize, 2);
x = off.x / (double)tilesize;
y = off.y / (double)tilesize;
tile2gps(&x, &y, currentloc.z);
p.lon = gpsloc.lon - x;
p.lat = gpsloc.lat - y;
return p;
}
int debug;
int shouldredraw = 0;
QLock shouldredrawl;
/* main thread */
void
checkcondredraw(void)
{
int b;
qlock(&shouldredrawl);
b = shouldredraw;
shouldredraw = 0;
qunlock(&shouldredrawl);
if (!b)
return;
nateredraw(0);
}
/* download threads */
void
imageupdated(void)
{
qlock(&shouldredrawl);
shouldredraw++;
qunlock(&shouldredrawl);
}
void
redrawmap(void)
{
requestimage(currentloc, imageupdated);
}
void
initimage(void)
{
Rectangle r;
if (mapimage) {
freeimage(mapimage);
mapimage = nil;
}
ncallcalcrect(mainwindow, screen, screen->r);
r.max.x = Dx(nimage->slot.r);
r.max.y = Dy(nimage->slot.r);
mapimagesize = r.max;
mapimage = allocimage(display, r, screen->chan, 0, DWhite);
nimage->image = mapimage;
debugprint("initimage: %P\n", mapimagesize);
}
void
eresized(int new)
{
if (new && getwindow(display, Refnone) < 0)
sysfatal("%r");
initimage();
redrawmap();
nateredraw(0);
}
int
exitclicked(Mouse, Nelem *, void*)
{
exits(nil);
}
static void
traperrout(void)
{
int p[2];
pipe(p);
dup(p[0], 2);
int fd = create("/srv/map.errout", OWRITE|ORCLOSE, 0666);
if (fd < 0)
sysfatal("create: %r");
fprint(fd, "%d\n", p[1]);
close(p[1]);
}
static int
inczoom(int n) {
int cz = zoom;
cz += n;
if (cz > maxzoom)
cz = maxzoom;
if (cz < 0)
cz = 0;
currentloc.z = cz;
cz = currentloc.z == zoom ? Cnil : Credraw;
zoom = currentloc.z;
currentloc = getbundle(gpsoff(), currentloc.z, &drawoffset);
return cz;
}
static void
calcoffset(double m, double *x, double *y)
{
double v;
double deg = gettiledeg();
if (x) *x = deg * m;
if (y) {
v = 1. - fabs(gpsloc.lat - 90) / 90.;
if (v < 0.1)
v = 0.1;
*y = deg * m * v;
}
}
static int
handlekeyboard(int kbdc)
{
double v;
double off = 0.5;
switch (kbdc) {
case Kdel:
case 'q':
exits(nil);
case '.':
return inczoom(+1);
case ',':
return inczoom(-1);
case Kleft:
calcoffset(off, &v, nil);
gpsloc.lon -= v;
goto Loc;
case Kright:
calcoffset(off, &v, nil);
gpsloc.lon += v;
goto Loc;
case Kup:
calcoffset(off, nil, &v);
gpsloc.lat += v;
goto Loc;
case Kdown:
calcoffset(off, nil, &v);
gpsloc.lat -= v;
goto Loc;
}
return Cnil;
Loc:
currentloc = getbundle(gpsoff(), currentloc.z, &drawoffset);
return Credraw;
}
void
handlecmd(int cmd)
{
switch (cmd) {
case Credraw:
redrawmap();
return;
case Cnil:
default:
break;
}
}
void
main(int argc, char **argv)
{
Event ev;
int timer;
int cmd;
ARGBEGIN{
case 'd':
debug++;
}ARGEND;
runchecks();
if (debug)
traperrout();
initmapfs();
gpsloc = getlocation();
if (initdraw(nil, nil, "map") < 0)
sysfatal("%r");
nateborders = 0;
natetracedraw = 0;
if (debug)
natedebugfd = 2;
einit(Emouse|Ekeyboard);
timer = etimer(0, 100);
nateinit();
NAssign(NWindow, &mainwindow, New_Window(nil))
->MakeRoot()
->Slot(NSlot(),
New_VBox(nil)
->Slot(NSlotx(TOPLEFT, FILLX),
New_HBox("menu")
->Slot(NSlotx(LEFT, 0),
New_Button("bexit")
->Border(1, display->black)
->Label("Exit")
->OnClick(exitclicked, nil)
)
->Slot(NSlotx(LEFT, 0),
New_Button("btest")
->Border(1, display->black)
->Label("Test")
)
)
->Slot(NSlot(),
New_Box(nil)
->Border(1, display->black)
->Slot(NSlot(),
NAssign(NImage, &nimage, New_Image("map"))
)
)
->Slot(NSlotx(LEFT, FILLX),
New_Box("status")
->Border(1, display->black)
->Padding(NMargin2(5, 5))
->Slot(NSlot(),
New_Label(nil)
->LabelFunc(getstatusline)
->Align(LEFT)
)
)
);
initimage();
currentloc = getbundle(gpsoff(), zoom, &drawoffset);
redrawmap();
for (;;) {
cmd = event(&ev);
if (cmd == timer) {
checkcondredraw();
continue;
}
switch (cmd) {
case Emouse:
if (ev.mouse.buttons & 4)
exits(nil);
else
natemouseevent(ev.mouse);
break;
case Ekeyboard:
cmd = handlekeyboard(ev.kbdc);
handlecmd(cmd);
break;
}
}
}