ref: bf716fa7786ee20a1e6c5bb2b80a3981f430fc43
dir: /geojson.c/
#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; extern int tilesize; 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 GBundle jpos; static int renderjsontype(JSON*); static void drawline(GPos f, GPos t) { GBundle fb, tb; Point fo, to; fb = getbundle(f, jpos.z, &fo); tb = getbundle(t, jpos.z, &to); fb.x -= jpos.x; fb.y -= jpos.y; tb.x -= jpos.x; tb.y -= jpos.y; fo.x = fb.x * tilesize + fb.x; fo.y = fb.y * tilesize + fb.y; to.x = tb.x * tilesize + tb.x; to.y = tb.y * tilesize + tb.y; if (!ptinrect(fo, mapimage->r)) return; if (!ptinrect(to, mapimage->r)) return; debugprint("jsline: %P - %P\n", fo, to); line(mapimage, fo, to, Endsquare, Endsquare, 0, display->black, ZP); } 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) { GPos p; GBundle b; Point off; if (!(j && j->t == JSONArray)) return 0; if (!jsoncoords(j, &p.lon, &p.lat)) return 0; debugprint("POINT: %f, %f\n", p.lon, p.lat); b = getbundle(p, jpos.z, &off); b.x -= jpos.x; b.y -= jpos.y; if (b.x < 0 || b.y < 0) return 1; off.x = b.x * tilesize + off.x; off.y = b.y * tilesize + off.y; if (!ptinrect(off, mapimage->r)) return 1; ellipse(mapimage, off, 5, 5, 1, display->black, ZP); return 1; } static int renderlinestring(JSON *j, JSON **l) { JSONEl *el; JSON *last = nil; double x1 = 0., y1 = 0., x2 = 0., y2 = 0.; GPos f, t; 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; f.lon = x1; f.lat = y1; t.lon = x2; t.lat = y2; drawline(f, t); } if (l) *l = last; return 1; } static int renderpolygon(JSON *j) { JSON *last; double x1, y1, x2, y2; GPos f, t; if (!(j && j->t == JSONArray)) return 0; if (!renderlinestring(j, &last)) return 0; if (!last) return 0; if (!jsoncoords(j->first->val, &x2, &y2)) return 0; if (!jsoncoords(last, &x1, &y1)) return 0; f.lon = x1; f.lat = y1; t.lon = x2; t.lat = y2; drawline(f, t); 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); 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); 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(GBundle pos) { if (!geojson) return; if (geojson->t != JSONObject) { jsonfree(geojson); geojson = nil; return; } debugprint("rendering geojson\n"); jpos = pos; 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; }