ref: 7c38fba56a72242a218c259981c57b7e451ce6b3
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;
JSONEl *el;
double x1, y1, x2, y2;
GPos f, t;
if (!(j && j->t == JSONArray))
return 0;
for (el = j->first; el; el = el->next) {
if (!renderlinestring(el->val, &last))
return 0;
if (!last)
return 0;
if (!jsoncoords(el->val->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;
}