shithub: map

Download patch

ref: cfddbc180a20062d424149829cc64fbf858b0812
parent: 5174bae840a2b91b2487c779dcebd643777ddb47
author: sirjofri <sirjofri@sirjofri.de>
date: Fri Apr 4 17:33:23 EDT 2025

adds geojson parse, no rendering yet

--- a/fns.h
+++ b/fns.h
@@ -4,6 +4,10 @@
 
 int parsepos(char *data, int ndata, GPos *pos, int *zoom);
 
+int handlegeojson(char *data, int ndata);
+void rendergeojson(GPos pos, int zoom);
+void cleargeojson(void);
+
 void lockmapimage(void);
 void unlockmapimage(void);
 
--- /dev/null
+++ b/geojson.c
@@ -1,0 +1,243 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <json.h>
+#include "dat.h"
+#include "fns.h"
+
+static char *Tcoords = "coordinates";
+static char *Ttype = "type";
+static char *Tfeature = "Feature";
+static char *Tfeatures = "features";
+static char *Tgeometry = "geometry";
+static char *Tfeaturecollection = "FeatureCollection";
+static char *Tpoint = "Point";
+static char *Tlinestring = "LineString";
+static char *Tpolygon = "Polygon";
+
+extern Image *mapimage;
+
+static JSON *geojson = nil;
+
+static int
+jsonnum(JSON *j, double *n)
+{
+	if (!(j && j->t == JSONNumber))
+		return 0;
+	*n = j->n;
+	return 1;
+}
+
+static int
+jsoncoords(JSON *j, double *x, double *y)
+{
+	JSONEl *el;
+	assert(x && y);
+	
+	if (j->t != JSONArray)
+		return 0;
+	
+	el = j->first;
+	if (el && el->val) {
+		if (!jsonnum(el->val, x))
+			return 0;
+	} else
+		return 0;
+	el = el->next;
+	if (el && el->val) {
+		if (!jsonnum(el->val, y))
+			return 0;
+	} else
+		return 0;
+	return 1;
+}
+
+static GPos jpos;
+static int jzoom;
+static int renderjsontype(JSON*);
+
+static int
+renderfeaturecollection(JSON *j)
+{
+	JSONEl *el;
+	int ret;
+	
+	if (!(j && j->t == JSONArray))
+		return 0;
+	
+	ret = 1;
+	for (el = j->first; el; el = el->next)
+		ret &= renderjsontype(el->val);
+	return ret;
+}
+
+static int
+renderpoint(JSON *j)
+{
+	double x, y;
+	int ret;
+	
+	if (!(j && j->t == JSONArray))
+		return 0;
+	
+	ret = jsoncoords(j, &x, &y);
+	debugprint("POINT: %f,  %f\n", x, y);
+	
+	return ret;
+}
+
+static int
+renderlinestring(JSON *j, JSON **l)
+{
+	JSONEl *el;
+	JSON *last = nil;
+	double x1 = 0., y1 = 0., x2 = 0., y2 = 0.;
+	if (!(j && j->t == JSONArray))
+		return 0;
+	
+	debugprint("LINESTRING\n");
+	for (el = j->first; el; el = el->next) {
+		if (last) {
+			x1 = x2;
+			y1 = y2;
+		}
+		if (!jsoncoords(el->val, &x2, &y2))
+			return 0;
+		if (!last) {
+			last = el->val;
+			continue;
+		}
+		last = el->val;
+		debugprint("LINE: %f, %f - %f %f\n", x1, y1, x2, y2);
+	}
+	
+	if (l)
+		*l = last;
+	return 1;
+}
+
+static int
+renderpolygon(JSON *j)
+{
+	JSON *last;
+	int ret;
+	double x1, y1, x2, y2;
+	if (!(j && j->t == JSONArray))
+		return 0;
+	
+	ret = renderlinestring(j, &last);
+	if (!ret)
+		return 0;
+	
+	if (!last)
+		return 0;
+	
+	if (!jsoncoords(j->first->val, &x2, &y2))
+		return ret;
+	if (!jsoncoords(last, &x1, &y1))
+		return ret;
+	debugprint("LINE: %f, %f - %f, %f\n", x1, y1, x2, y2);
+	
+	return 1;
+}
+
+static int
+renderfeaturegeometry(JSON *j)
+{
+	char *s;
+	JSON *type;
+	
+	if (!(j && j->t == JSONObject))
+		return 0;
+	
+	type = jsonbyname(j, Ttype);
+	if (!(type && type->t == JSONString))
+		return 0;
+	
+	s = jsonstr(type);
+	debugprint("parsing geo %s\n", s);
+	if (!s)
+		return 0;
+	if (strcmp(s, Tpoint) == 0)
+		return renderpoint(jsonbyname(j, Tcoords));
+	if (strcmp(s, Tlinestring) == 0)
+		return renderlinestring(jsonbyname(j, Tcoords), nil);
+	if (strcmp(s, Tpolygon) == 0)
+		return renderpolygon(jsonbyname(j, Tcoords));
+	return 0;
+}
+
+static int
+renderjsontype(JSON *j)
+{
+	JSON *type;
+	char *s;
+	
+	type = jsonbyname(j, Ttype);
+	if (!(type && type->t == JSONString))
+		return 0;
+	
+	s = jsonstr(type);
+	debugprint("parsing %s\n", s);
+	if (!s)
+		return 0;
+	if (strcmp(s, Tfeaturecollection) == 0)
+		return renderfeaturecollection(jsonbyname(j, Tfeatures));
+	if (strcmp(s, Tfeature) == 0)
+		return renderfeaturegeometry(jsonbyname(j, Tgeometry));
+	return 0;
+}
+
+void
+rendergeojson(GPos pos, int zoom)
+{
+	if (!geojson)
+		return;
+	
+	if (geojson->t != JSONObject) {
+		jsonfree(geojson);
+		geojson = nil;
+		return;
+	}
+	
+	debugprint("rendering geojson\n");
+	jpos = pos;
+	jzoom = zoom;
+	
+	if (!renderjsontype(geojson)) {
+		jsonfree(geojson);
+		geojson = nil;
+	}
+}
+
+int
+handlegeojson(char *data, int ndata)
+{
+	char *s;
+	
+	if (geojson) {
+		jsonfree(geojson);
+		geojson = nil;
+	}
+	
+	s = mallocz(ndata + 1, 1);
+	if (!s)
+		sysfatal("%r");
+	
+	memcpy(s, data, ndata);
+	
+	geojson = jsonparse(s);
+	free(s);
+	
+	if (geojson)
+		debugprint("got geojson data\n");
+	
+	return !!geojson;
+}
+
+void
+cleargeojson()
+{
+	jsonfree(geojson);
+	geojson = nil;
+}
--- a/map.c
+++ b/map.c
@@ -215,6 +215,10 @@
 void
 imageupdated(void)
 {
+	lockmapimage();
+	rendergeojson(gpsoff(), currentloc.z);
+	unlockmapimage();
+	
 	qlock(&shouldredrawl);
 	shouldredraw++;
 	qunlock(&shouldredrawl);
@@ -386,7 +390,7 @@
 	GPos pos;
 	int z;
 	if (pm->ndata < 0)
-		goto Out;
+		goto Backout;
 	
 	if (!parsepos(pm->data, pm->ndata, &pos, &zoom))
 		goto Out;
@@ -397,8 +401,13 @@
 		currentloc.z = zoom = z;
 	locupdated();
 	handlecmd(Credraw);
+	goto Backout;
 	
 Out:
+	if (!handlegeojson(pm->data, pm->ndata))
+		debugprint("geojson: %r\n");
+	
+Backout:
 	plumbfree(pm);
 }
 
--- a/mkfile
+++ b/mkfile
@@ -8,6 +8,7 @@
 	gps.$O\
 	img.$O\
 	parse.$O\
+	geojson.$O\
 
 HFILES=fns.h dat.h