shithub: map

ref: cfddbc180a20062d424149829cc64fbf858b0812
dir: /geojson.c/

View raw version
#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;
}