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