ref: 7b6082bf29c9239d93f33c55103668f7046189ca
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 *Tgeometries = "geometries"; static char *Tfeaturecollection = "FeatureCollection"; static char *Tpoint = "Point"; static char *Tmultipoint = "MultiPoint"; static char *Tlinestring = "LineString"; static char *Tmultilinestring = "MultiLineString"; static char *Tpolygon = "Polygon"; static char *Tmultipolygon = "MultiPolygon"; static char *Tgeocollection = "GeometryCollection"; static char *Enumber = "expected number"; static char *Earray = "expected array"; static char *Ecoords = "expected coords"; static char *Eobject = "expected object"; static char *Estring = "expected string"; static int jisarray(JSON *j) { if (!(j && j->t == JSONArray)) { werrstr(Earray); return 0; } return 1; } static int jisnumber(JSON *j) { if (!(j && j->t == JSONNumber)) { werrstr(Earray); return 0; } return 1; } static int jisobject(JSON *j) { if (!(j && j->t == JSONObject)) { werrstr(Eobject); return 0; } return 1; } static int jisstring(JSON *j) { if (!(j && j->t == JSONString)) { werrstr(Estring); return 0; } return 1; } extern Image *mapimage; extern int tilesize; static JSON *geojson = nil; static GBundle jpos; static int renderjsontype(JSON*); static int jsonnum(JSON *j, double *n) { if (!jisnumber(j)) return 0; *n = j->n; return 1; } static int jsoncoords(JSON *j, double *x, double *y) { JSONEl *el; assert(x && y); if (!jisarray(j)) return 0; el = j->first; if (el && el->val) { if (!jsonnum(el->val, x)) return 0; } else { werrstr(Ecoords); return 0; } el = el->next; if (el && el->val) { if (!jsonnum(el->val, y)) return 0; } else { werrstr(Ecoords); return 0; } return 1; } static int coordspoint(JSON *j, Point *point) { GPos p; GBundle b; Point o; if (!jsoncoords(j, &p.lon, &p.lat)) return 0; b = getbundle(p, jpos.z, &o); b.x -= jpos.x; b.y -= jpos.y; o.x = b.x * tilesize + o.x; o.y = b.y * tilesize + o.y; *point = o; return 1; } static int topointarray(JSON *j, Point **arr, int *np) { JSONEl *el; int n; if (!jisarray(j)) return 0; *np = 0; for (el = j->first; el; el = el->next) (*np)++; if (!*np) { *arr = nil; return 1; } *arr = mallocz(*np * sizeof(Point), 1); if (!*arr) sysfatal("topointarray: %r"); n = 0; for (el = j->first; el; el = el->next) { if (!coordspoint(el->val, &(*arr)[n++])) return 0; } return 1; } 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 + fo.x; fo.y = fb.y * tilesize + fo.y; to.x = tb.x * tilesize + to.x; to.y = tb.y * tilesize + to.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, 2, display->black, ZP); } static int renderfeaturecollection(JSON *j) { JSONEl *el; int ret; if (!jisarray(j)) 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 (!jisarray(j)) 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 rendermpoint(JSON *j) { JSONEl *el; if (!jisarray(j)) return 0; for (el = j->first; el; el = el->next) { if (!renderpoint(el->val)) return 0; } return 1; } static int renderlinestring(JSON *j) { JSONEl *el; JSON *last = nil; double x1 = 0., y1 = 0., x2 = 0., y2 = 0.; GPos f, t; if (!jisarray(j)) 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); } return 1; } static int rendermlinestring(JSON *j) { JSONEl *el; if (!jisarray(j)) return 0; for (el = j->first; el; el = el->next) { if (!renderlinestring(el->val)) return 0; } return 1; } static int renderpolygon(JSON *j) { JSONEl *el; Image *img; Point *pts; int np; if (!jisarray(j)) return 0; img = allocimage(display, mapimage->r, GREY1, 0, DBlack); if (!img) sysfatal("%r"); for (el = j->first; el; el = el->next) { if (!topointarray(el->val, &pts, &np)) return 0; fillpoly(img, pts, np, 1, cwhite, ZP); free(pts); pts = nil; } draw(mapimage, img->r, cgreen, img, ZP); freeimage(img); return 1; } static int rendermpolygon(JSON *j) { JSONEl *el; if (!jisarray(j)) return 0; for (el = j->first; el; el = el->next) { if (!renderpolygon(el->val)) return 0; } return 1; } static int rendergeocollection(JSON *j) { JSONEl *el; if (!jisarray(j)) return 0; for (el = j->first; el; el = el->next) { if (!renderjsontype(el->val)) return 0; } return 1; } static int renderjsontype(JSON *j) { JSON *type; char *s; type = jsonbyname(j, Ttype); if (!jisstring(type)) return 0; s = jsonstr(type); if (!s) { werrstr("empty string"); return 0; } if (strcmp(s, Tfeaturecollection) == 0) return renderfeaturecollection(jsonbyname(j, Tfeatures)); if (strcmp(s, Tfeature) == 0) return renderjsontype(jsonbyname(j, Tgeometry)); if (strcmp(s, Tpoint) == 0) return renderpoint(jsonbyname(j, Tcoords)); if (strcmp(s, Tmultipoint) == 0) return rendermpoint(jsonbyname(j, Tcoords)); if (strcmp(s, Tlinestring) == 0) return renderlinestring(jsonbyname(j, Tcoords)); if (strcmp(s, Tmultilinestring) == 0) return rendermlinestring(jsonbyname(j, Tcoords)); if (strcmp(s, Tpolygon) == 0) return renderpolygon(jsonbyname(j, Tcoords)); if (strcmp(s, Tmultipolygon) == 0) return rendermpolygon(jsonbyname(j, Tcoords)); if (strcmp(s, Tgeocollection) == 0) return rendergeocollection(jsonbyname(j, Tgeometries)); werrstr("invalid type: %s", s); 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)) { debugprint("invalid geojson: %r\n"); 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; }