shithub: map

Download patch

ref: 2376db3167bee07ce18758a32ef05916eb325a3f
parent: 5b8b0cbeb3461b0a710584ee77f1cb6c501a5406
author: sirjofri <sirjofri@sirjofri.de>
date: Fri Mar 28 07:34:36 EDT 2025

working version, using mapfs

--- a/dat.h
+++ b/dat.h
@@ -2,6 +2,11 @@
 typedef struct GBundle GBundle;
 typedef struct GProvider GProvider;
 
+extern Image* mapimage;
+extern int tilesize;
+extern Point drawoffset;
+extern int debug;
+
 struct GPos {
 	double lon;
 	double lat;
@@ -11,8 +16,4 @@
 	int x;
 	int y;
 	int z;
-};
-
-struct GProvider {
-	char* (*formaturl)(GBundle);
 };
--- a/fns.h
+++ b/fns.h
@@ -1,9 +1,10 @@
-int lon2tilex(double lon, int z);
-int lat2tiley(double lat, int z);
-double tilex2long(int x, int z);
-double tiley2lat(int y, int z);
-
-GBundle getbundle(GPos pos, int zoom);
+GBundle getbundle(GPos pos, int zoom, Point *offset);
 GPos getlocation(void);
 
-GProvider *getprovider(void);
+void lockmapimage(void);
+void unlockmapimage(void);
+
+typedef void (*ImageUpdated)(void);
+void requestimage(GBundle from, ImageUpdated);
+
+void debugprint(char *fmt, ...);
--- a/gps.c
+++ b/gps.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <draw.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -17,8 +18,10 @@
 	ret.lat = 0.;
 	
 	fd = open("/mnt/gps/position", OREAD);
-	if (fd < 0)
+	if (fd < 0) {
+		debugprint("unable to open gps: %r\n");
 		return ret;
+	}
 	
 	if ((n = read(fd, buf, 256)) <= 0) {
 		fprint(2, "read error: %r\n");
@@ -32,7 +35,7 @@
 	if (!quality)
 		return ret;
 	
-	if (getfields(buf, fields, 9, 1, " ") != 9) {
+	if (getfields(buf, fields, 9, 1, " 	") != 9) {
 		fprint(2, "read error: invalid fields\n");
 		return ret;
 	}
@@ -39,5 +42,6 @@
 	
 	ret.lon = strtod(fields[3], &nop);
 	ret.lat = strtod(fields[4], &nop);
+	debugprint("GPS: %f %f\n", ret.lon, ret.lat);
 	return ret;
 }
--- a/map.c
+++ b/map.c
@@ -2,6 +2,7 @@
 #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>
@@ -13,37 +14,126 @@
 #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);
+}
+
 NWindow *mainwindow;
 NImage *nimage;
 
-Image *testimage;
+enum {
+	Cnil,
+	Credraw,
+};
 
+GPos gpsloc;
+GBundle currentloc;
+Point drawoffset;
+int maxzoom = 8;
+int zoom = 5;
+
+int tilesize = 256;
+
+Image *mapimage;
+QLock mapimagelock;
+
+void
+lockmapimage(void)
+{
+	qlock(&mapimagelock);
+}
+void
+unlockmapimage(void)
+{
+	qunlock(&mapimagelock);
+}
+
 int debug;
 
+int shouldredraw = 0;
+QLock shouldredrawl;
+
+/* main thread */
 void
-inittestimage(void)
+checkcondredraw(void)
 {
-	Image *r, *g;
-	testimage = allocimage(display, Rect(0, 0, 100, 100), screen->chan, 1, DWhite);
-	r = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DRed);
-	g = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DGreen);
-	draw(testimage, Rect(0, 0, 50, 50), r, nil, ZP);
-	draw(testimage, Rect(50, 50, 100, 100), g, nil, ZP);
-	freeimage(r);
-	freeimage(g);
+	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);
+	
+	mapimage = allocimage(display, r, screen->chan, 0, DWhite);
+	nimage->image = mapimage;
+}
+
+void
 eresized(int new)
 {
+	Point isize;
 	if (new && getwindow(display, Refnone) < 0)
 		sysfatal("%r");
 	
-	nateredraw(1);
+	freeimage(mapimage);
+	nimage->image = nil;
+	ncallcalcrect(mainwindow, screen, screen->r);
+	isize.x = Dx(nimage->slot.r);
+	isize.y = Dy(nimage->slot.r);
+	
+	debugprint("resized image: %P\n", isize);
+	
+	mapimage = allocimage(display, Rect(0, 0, isize.x, isize.y), screen->chan, 0, DWhite);
+	nimage->image = mapimage;
+	
+	redrawmap();
+	
+	nateredraw(0);
 }
 
 int
-exitclicked(Mouse, Nelem *el, void*)
+exitclicked(Mouse, Nelem *, void*)
 {
 	exits(nil);
 }
@@ -61,12 +151,73 @@
 	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(gpsloc, currentloc.z, &drawoffset);
+	return cz;
+}
+
+static int
+handlekeyboard(int kbdc)
+{
+	double off = 10./(currentloc.z <= 0 ? 1 : currentloc.z);
+	
+	switch (kbdc) {
+	case Kdel:
+	case 'q':
+		exits(nil);
+	case '.':
+		return inczoom(+1);
+	case ',':
+		return inczoom(-1);
+	case Kleft:
+		gpsloc.lon -= off;
+		goto Loc;
+	case Kright:
+		gpsloc.lon += off;
+		goto Loc;
+	case Kup:
+		gpsloc.lat += off;
+		goto Loc;
+	case Kdown:
+		gpsloc.lat -= off;
+		goto Loc;
+	}
+	return Cnil;
+
+Loc:
+	currentloc = getbundle(gpsloc, 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 z = 0;
-	char *url;
+	int timer;
+	int cmd;
 	
 	ARGBEGIN{
 	case 'd':
@@ -73,64 +224,72 @@
 		debug++;
 	}ARGEND;
 	
+	if (debug)
+		traperrout();
+
+	gpsloc = getlocation();
+	currentloc = getbundle(gpsloc, zoom, &drawoffset);
+	
 	if (initdraw(nil, nil, "map") < 0)
 		sysfatal("%r");
 	
+	nateborders = 0;
+	natetracedraw = debug;
 	if (debug)
-		traperrout();
+		natedebugfd = 2;
 	
-	nateborders = 1;
+	einit(Emouse|Ekeyboard);
+	timer = etimer(0, 100);
 	
-	einit(Emouse);
 	nateinit();
 	
-	inittestimage();
-	
 	NAssign(NWindow, &mainwindow, New_Window(nil))
 	->MakeRoot()
-	->Slot(
+	->Slot(NSlot(),
 		New_VBox(nil)
-		->Slot(
+		->Slot(NSlotx(TOPLEFT, FILLX),
 			New_HBox("menu")
-			->AutoHeight(1)
-			->Slot(
-				New_Button(nil)
-				->AutoSize(1)
+			->Slot(NSlotx(LEFT, 0),
+				New_Button("bexit")
 				->Border(1, display->black)
 				->Label("Exit")
 				->OnClick(exitclicked, nil)
 			)
-			->Slot(
-				New_Button(nil)
-				->AutoSize(1)
-				->Label("Test")
+			->Slot(NSlotx(LEFT, 0),
+				New_Button("btest")
 				->Border(1, display->black)
+				->Label("Test")
 			)
 		)
-		->Slot(
+		->Slot(NSlot(),
 			New_Box(nil)
 			->Border(1, display->black)
-			->Size(Pt(200, 300))
-			->Slot(
+			->Slot(NSlot(),
 				NAssign(NImage, &nimage, New_Image("map"))
-				->Image(testimage)
 			)
 		)
-		->Slot(
-			New_Box(nil)
+		->Slot(NSlotx(LEFT, FILLX),
+			New_Box("status")
 			->Border(1, display->black)
-			->Size(Pt(500, 30))
-			->Slot(
+			->Padding(NMargin2(5, 5))
+			->Slot(NSlot(),
 				New_Label(nil)
 				->Label("Status Line")
+				->Align(LEFT)
 			)
 		)
 	);
 	
-	nateredraw(1);
+	initimage();
+	redrawmap();
 	
 	for (;;) {
-		switch (event(&ev)) {
+		cmd = event(&ev);
+		if (cmd == timer) {
+			checkcondredraw();
+			continue;
+		}
+		switch (cmd) {
 		case Emouse:
 			if (ev.mouse.buttons & 4)
 				exits(nil);
@@ -137,13 +296,10 @@
 			else
 				natemouseevent(ev.mouse);
 			break;
+		case Ekeyboard:
+			cmd = handlekeyboard(ev.kbdc);
+			handlecmd(cmd);
+			break;
 		}
 	}
-	
-	GPos loc = getlocation();
-	GBundle bundle = getbundle(loc, z);
-	GProvider *prov = getprovider();
-	
-	url = prov->formaturl(bundle);
-	print("%s\n", url);
 }
--- a/mkfile
+++ b/mkfile
@@ -1,11 +1,13 @@
 </$objtype/mkfile
 
+BIN=/$objtype/bin
 TARG=map
 OFILES=\
 	map.$O\
-	osm.$O\
+	tile.$O\
 	gps.$O\
+	img.$O\
 
-HFILES=fns.h
+HFILES=fns.h dat.h
 
 </sys/src/cmd/mkone
--- a/osm.c
+++ /dev/null
@@ -1,61 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "dat.h"
-#include "fns.h"
-
-static double
-asinh(double x)
-{
-	double s = sqrt(x*x + 1);
-	return log(x + s);
-}
-
-int
-lon2tilex(double lon, int z)
-{
-	return (int)(floor((lon + 180.0) / 360.0 * (1<<z)));
-}
-
-int
-lat2tiley(double lat, int z)
-{
-	double latrad = lat * PI/180.0;
-	return (int)(floor((1.0 - asinh(tan(latrad)) / PI) / 2.0 * (1<<z)));
-}
-
-double tilex2long(int x, int z)
-{
-	return x / (double)(1<<z) * 360.0 - 180.0;
-}
-
-double tiley2lat(int y, int z)
-{
-	double n = PI - 2.0 * PI * y / (double)(1<<z);
-	return 180.0 / PI * atan(0.5 * (exp(n) - exp(-n)));
-}
-
-GBundle
-getbundle(GPos pos, int z)
-{
-	GBundle ret;
-	ret.x = lon2tilex(pos.lon, z);
-	ret.y = lat2tiley(pos.lat, z);
-	ret.z = z;
-	return ret;
-}
-
-static char*
-defaultformaturl(GBundle b)
-{
-	return smprint("https://tile.openstreetmap.org/%d/%d/%d.png", b.z, b.x, b.y);
-}
-
-static GProvider defaultprovider = {
-	.formaturl = defaultformaturl,
-};
-
-GProvider*
-getprovider()
-{
-	return &defaultprovider;
-}
--- /dev/null
+++ b/tile.c
@@ -1,0 +1,52 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+static double
+asinh(double x)
+{
+	double s = sqrt(x*x + 1);
+	return log(x + s);
+}
+
+int
+lon2tilex(double lon, int z, int *offset)
+{
+	double tile = (lon + 180.0) / 360.0 * (1<<z);
+	int t = floor(tile);
+	*offset = (tile - t) * tilesize;
+	return t;
+}
+
+int
+lat2tiley(double lat, int z, int *offset)
+{
+	double latrad = lat * PI/180.0;
+	double tile = (1.0 - asinh(tan(latrad)) / PI) / 2.0 * (1<<z);
+	int t = floor(tile);
+	*offset = (tile - t) * tilesize;
+	return t;
+}
+
+double tilex2long(int x, int z)
+{
+	return x / (double)(1<<z) * 360.0 - 180.0;
+}
+
+double tiley2lat(int y, int z)
+{
+	double n = PI - 2.0 * PI * y / (double)(1<<z);
+	return 180.0 / PI * atan(0.5 * (exp(n) - exp(-n)));
+}
+
+GBundle
+getbundle(GPos pos, int z, Point *offset)
+{
+	GBundle ret;
+	ret.x = lon2tilex(pos.lon, z, &offset->x);
+	ret.y = lat2tiley(pos.lat, z, &offset->y);
+	ret.z = z;
+	return ret;
+}