#include <cassert>
#include <cmath>
#include <core/os/file_access.h>
#include <core/io/json.h>
#include <core/math/geometry.h>
#include <core/resource.h>
#include <core/variant_parser.h>
#include <scene/2d/canvas_item.h>
#include <modules/voronoi/voronoi.h>
#include <modules/opensimplex/open_simplex_noise.h>
#include "road_grid.h"

RoadGrid::RoadGrid()
{
	grid_width = 16;
	grid_height = 16;
}

RoadGrid::~RoadGrid()
{
}

/* TODO: constants, configuration */
Dictionary RoadDiagram::build_diagram(Ref<RandomNumberGenerator> rnd, int npatches, int center_count, int center_step, int spread, int dim)
{
	printf("build_diagram %d %d %d %d %d\n", npatches, center_count, center_step, spread, dim);
	Vector<Vector2i> centers;
	/* zero is always used */
	centers.push_back(Vector2i(0, 0));
	float sa = rnd->randf() * 2.0 * Math_PI;
	int i, bad = 0, cx, cp;
	while (centers.size() < center_count) {
		int center_x = center_step * (int)((rnd->randi() % spread) - spread / 2);
		int center_y = center_step * (int)((rnd->randi() % spread) - spread / 2);
		center_x = CLAMP(center_x, -dim, dim);
		center_y = CLAMP(center_y, -dim, dim);
		Vector2i c(center_x, center_y);
		if (centers.find(c) < 0) {
			centers.push_back(c);
			bad = 0;
		} else
			bad++;
		if (bad > 1000)
			break;
	}
	assert(centers.size() > 1);
	Vector<Vector2> points;
	for (cx = 0; cx < centers.size(); cx++) {
		float maxr = 0.0f;
		for (cp = 0; cp < npatches * 8; cp++) {
			float a = sa + sqrtf((float)cp) * 8.0f;
			float r = (cp == 0) ? 0.0f : 100.0f + (float)cp * 100.0f + 50.0f * rnd->randf();
			float x = floor(cosf(a) * r + (float)centers[cx].x);
			float y = floor(sinf(a) * r + (float)centers[cx].y);
			if (maxr < r)
				maxr = r;
			Vector2 p(x, y);
			if (points.find(p) < 0)
				points.push_back(p);
		}
		struct cluster cst;
		cst.c = centers[cx];
		cst.r = maxr + 50.0f;
		clusters.push_back(cst);
	}
	PoolVector<Vector2> cpoints;
	cpoints.resize(points.size());
	memcpy(cpoints.write().ptr(), points.ptr(), points.size() * sizeof(Vector2));

	Dictionary diagram = Voronoi::get_singleton()->generate_diagram(cpoints, 11);
	return diagram;
}
const List<struct cluster> &RoadDiagram::get_clusters() const
{
	return clusters;
}
const Vector<struct map_site> &RoadDiagram::get_map_sites() const
{
	return map_sites;
}
const Vector<Vector2> &RoadDiagram::get_diagram_vertices() const
{
	return diagram_vertices;
}
const Vector<struct half_edge *> &RoadDiagram::get_map_hedges() const
{
	return map_hedges;
}
bool RoadGrid::segment_intersects_rect(const Vector2 &a, const Vector2 &b, const Rect2 &rect)
{
	real_t min = 0, max = 1;
	const Vector2 &p_from = a;
	const Vector2 &p_to = b;

	for (int i = 0; i < 2; i++) {
		real_t seg_from = p_from[i];
		real_t seg_to = p_to[i];
		real_t box_begin = rect.position[i];
		real_t box_end = box_begin + rect.size[i];
		real_t cmin, cmax;

		if (seg_from < seg_to) {
			if (seg_from > box_end || seg_to < box_begin) {
				return false;
			}
			real_t length = seg_to - seg_from;
			cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0;
			cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1;

		} else {
			if (seg_to > box_end || seg_from < box_begin) {
				return false;
			}
			real_t length = seg_to - seg_from;
			cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0;
			cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1;
		}

		if (cmin > min) {
			min = cmin;
		}
		if (cmax < max) {
			max = cmax;
		}
		if (max < min) {
			return false;
		}
	}

	return true;
}

/* This is heavy when rendered on top of 3D viewport! */
void RoadGrid::draw_debug(Node *drawable, int size_x, int size_y) const
{
	int i, j, k;
	CanvasItem *ci = Object::cast_to<CanvasItem>(drawable);
	if (!ci)
		return;
	if (bounds.size.x <= 0.0f || bounds.size.y <= 0.0f) {
		printf("zero bounds %f %f\n", bounds.size.x, bounds.size.y);
		return;
	}
	for (i = 0; i < map_sites.size(); i++) {
		Vector2 a = (map_sites[i].pos - bounds.position) * Vector2(size_x, size_y) / bounds.size;
		ci->draw_circle(a, 4.0f, Color(0.0f, 0.5f, 0.5f, 1.0f));
	}
	for (i = 0; i < map_hedges.size(); i++) {
		Vector2 xa = diagram_vertices[map_hedges[i]->a];
		Vector2 xb = diagram_vertices[map_hedges[i]->b];
		Vector2 a = (xa - bounds.position) * Vector2(size_x, size_y) / bounds.size;
		Vector2 b = (xb - bounds.position) * Vector2(size_x, size_y) / bounds.size;
		ci->draw_line(a, b, Color(0.0f, 0.7f, 0.7f, 1.0f), 3.0f, true);
	}
	Rect2i g = rect_to_grid(bounds);
	for (i = g.position.y - 1; i < g.position.y + g.size.y + 1; i++) {
		for (j = g.position.x - 1; j < g.position.x + g.size.x + 1; j++) {
			if (hedge_grid.has(j, i)) {
				const Vector<struct half_edge *> &items = hedge_grid.get(j, i);
				for (k = 0; k < items.size(); k++) {
					struct half_edge *he = items[k];

					assert(he->a >= 0);
					assert(he->b >= 0);
					assert(he->a != he->b);
					assert(he->site >= 0);

					Vector2 xa = diagram_vertices[he->a];
					Vector2 xb = diagram_vertices[he->b];
					const struct map_site *site = &map_sites[he->site];
					Vector2 pos = (site->pos - bounds.position) * Vector2(size_x, size_y) / bounds.size;
					ci->draw_circle(pos, 3.0f, Color(0.2f, 0.2f, 0.5f, 1.0f));
					Vector2 a = (xa - bounds.position) * Vector2(size_x, size_y) / bounds.size;
					Vector2 b = (xb - bounds.position) * Vector2(size_x, size_y) / bounds.size;
					ci->draw_line(a, b, Color(0.2f, 0.2f, 0.7f, 1.0f), 2.0f, true);
				}
			}
		}
	}
}

void RoadDiagram::index_site(struct map_site *site)
{
	int i;
	site->vertices_ind.resize(site->vertices.size());
	site->polygon_ind.resize(site->polygon.size());
	/* slow as fuck */
	for (i = 0; i < site->vertices.size(); i++) {
		Vector2 v = site->vertices[i].snapped(Vector2(2.0f, 2.0f));
		int idx = diagram_vertices.find(v);
		if (idx < 0) {
			idx = diagram_vertices.size();
			diagram_vertices.push_back(v);
		}
		site->vertices_ind.write[i] = idx;
	}
	for (i = 0; i < site->polygon.size(); i++) {
		Vector2 v = site->polygon[i].snapped(Vector2(2.0f, 2.0f));
		int idx = diagram_vertices.find(v);
		if (idx < 0) {
			idx = diagram_vertices.size();
			diagram_vertices.push_back(v);
		}
		site->polygon_ind.write[i] = idx;
		site->rect.expand_to(Vector2i((int)v.x, (int)v.y));
	}
	site->rect.grow(1);
	site->hedges.resize(site->polygon.size());
	int count = 0;
	for (i = 0; i < site->polygon.size(); i++) {
		int idx1 = site->polygon_ind[i];
		int idx2 = site->polygon_ind[(i + 1) % site->polygon.size()];
		if (idx1 == idx2)
			continue;
		struct half_edge he;
		he.a = idx1;
		he.b = idx2;
		he.site = site->index;
		/* use length to decide */
		he.length = diagram_vertices[idx1].distance_to(diagram_vertices[idx2]);
		if (he.length < 50.0f)
			he.depth = 3.0f;
		else if (he.length < 100.0f)
			he.depth = 6.0f;
		else if (he.length < 200.0f)
			he.depth = 12.0f;
		else
			he.depth = 24.0f;
		site->hedges.write[count++] = he;
	}
	site->hedges.resize(count);
}

void RoadDiagram::process_diagram(const Dictionary &diagram)
{
	const Array &sites = diagram["sites"];
	int i, j;
	map_sites.resize(sites.size());
	int hedge_count = 0, hedge_idx;
	printf("start processing sites\n");
	for (i = 0; i < sites.size(); i++) {
		struct map_site site;
		/* We use Dictionary to build native structure only once,
		 * then we use native data. */
		const Dictionary &site_data = sites[i];
		const Array &graphedges = site_data["graphedges"];
		printf("processing site: %d\n", i);
		site.graphedges.resize(graphedges.size());
		for (j = 0; j < graphedges.size(); j++) {
			const Dictionary &ge_data = graphedges[j];
			struct graphedge ge;
			ge.a = ge_data["a"];
			ge.b = ge_data["b"];
			ge.edge = ge_data["edge"];
			site.graphedges.write[j] = ge;
		}
	       	site.index = i;
		site.diagram_index = site_data["index"];
	       	site.pos = site_data["pos"];
		site.polygon = site_data["polygon"];
		site.vertices = site_data["vertices"];
		site.site_type = map_site::SITE_UNASSIGNED;
		site.cluster = -1;
		index_site(&site);
		hedge_count += site.hedges.size();
		map_sites.write[i] = site;
	}
	printf("processing sites done\n");
	/* Fill global half edges array and put in grid */
	printf("processing %d half edges\n", hedge_count);
	map_hedges.resize(hedge_count);
	hedge_idx = 0;
	for (i = 0; i < map_sites.size(); i++) {
		for (j = 0; j < map_sites[i].hedges.size(); j++) {
			/* bad bad constness */
			struct half_edge *hedge = &map_sites.write[i].hedges.write[j];
			map_hedges.write[hedge_idx] = hedge;
			hedge_idx++;
		}
	}
	printf("processing half edges done\n");
	classify_sites();
	printf("processing done, sites count: %d\n", map_sites.size());
}
RoadDiagram::RoadDiagram()
{
	class_sizes[map_site::SITE_EMPTY] = 10000;
	class_sizes[map_site::SITE_FARM] = 100000;
	class_sizes[map_site::SITE_TOWN] = 240000;
	class_sizes[map_site::SITE_FOREST] = 1000000;
	class_sizes[map_site::SITE_UNASSIGNED] = 2000000;
}

void RoadDiagram::build(Ref<RandomNumberGenerator> rnd,
		int npatches, int center_count, int center_step,
		int spread, int dim)
{
	Dictionary diagram = build_diagram(rnd, npatches, center_count, center_step,
			spread, dim);
	process_diagram(diagram);
}
void RoadGrid::build(Ref<Curve> curve, Ref<FastNoiseLite> noise)
{
	int i, j;
	RoadDiagram rd;
	rnd.instance();
	rnd->randomize();
	printf("build_diagram\n");
	rd.build(rnd, 8, 2, 100, 100, 500);
	printf("build_diagram done\n");
	const List<struct cluster> &cl = rd.get_clusters();
	const List<struct cluster>::Element *e = cl.front();
	for (e = cl.front(); e; e = e->next())
		clusters.push_back(e->get());
	map_sites.append_array(rd.get_map_sites());
	diagram_vertices.append_array(rd.get_diagram_vertices());
	map_hedges.append_array(rd.get_map_hedges());
	for (i = 0; i < map_hedges.size(); i++) {
		struct half_edge *hedge = map_hedges.write[i];
		add_hedge_to_grid(hedge);
	}
	printf("%d %d\n", curve.is_valid(), noise.is_valid());
	assert(curve.is_valid() && noise.is_valid());
	if (curve.is_valid() && noise.is_valid()) {
		printf("building 3rd dimention\n");
		generate_3d_vertices(curve, noise);
		for (i = 0; i < map_sites.size(); i++) {
			float max_height = -10000.0f;
			float min_height = 10000.0f;
			for (j = 0; j < map_sites[i].polygon_ind.size(); j++) {
				float y = vertices[map_sites[i].polygon_ind[j]].y;
				if (max_height < y)
					max_height = y;
				if (min_height > y)
					min_height = y;
			}
			map_sites.write[i].avg_height = min_height * 0.7f + max_height * 0.3f;
		}
		generate_building_positions();
		printf("building 3rd dimention done\n");
	}
	keep_seed = rnd->get_state();
}

Vector2 RoadGrid::get_influence(int x, int y, float radius) const
{
	int rd = (int)(radius / grid_width) + 1;
	Vector<struct half_edge *> hlist;
	const List<struct half_edge *>::Element *e;
	int i = 0, j = 0;
	for (i = -rd; i < rd + 1; i++)
		for (j = -rd; j < rd + 1; j++) {
			if (hedge_grid.has(x / grid_width + i, y / grid_height + j)) {
				const Vector<struct half_edge *> &tmp = hedge_grid.get(x / grid_width + i, y / grid_height + j);
				hlist.append_array(tmp);
			}

		}
	if (hlist.size() == 0)
		return Vector2();
	for (i = 0; i < hlist.size(); i++) {
		struct half_edge *he = hlist[i];
		Vector2 a = diagram_vertices[he->a];
		Vector2 b = diagram_vertices[he->b];
		Vector2 p(x, y);
		Vector2 seg[] = {a, b};
		Vector2 pt = Geometry::get_closest_point_to_segment_2d(p, seg);
		float d = pt.distance_squared_to(p);
		if (d < radius * radius + he->depth * he->depth) {
			Vector2 ret;
			ret.x = 1.0f;
			assert(vertices.size() > he->a);
			assert(vertices.size() > he->b);
			float h1 = vertices[he->a].y;
			float h2 = vertices[he->b].y;
			float l = he->length;
			assert(l > 0.0f);
			float m1 = pt.distance_to(a) / l;
			float m2 = 1.0f - m1;
			m2 = CLAMP(m2, 0.0f, 1.0f);
			float h = h1 * (1.0f - m1) + h2 * (1.0f - m2);
			ret.y = h - 2.5f;
			return ret;
		}
	}
	return Vector2();
}

void RoadGrid::_bind_methods()
{
	ClassDB::bind_method(D_METHOD("draw_debug", "drawable", "size_x", "size_y"), &RoadGrid::draw_debug);
	ClassDB::bind_method(D_METHOD("get_influence", "x", "y", "radius"), &RoadGrid::get_influence);
	ClassDB::bind_method(D_METHOD("build", "curve", "noise"), &RoadGrid::build);
}

int RoadGrid::find_edge(int a, int b)
{
	int i;
	for (i = 0; i < map_hedges.size(); i++) {
		if (map_hedges[i]->a == a &&
				map_hedges[i]->b == b)
			return i;
	}
	return -1;
}
void RoadGrid::setup_vshapes()
{
	int i, j;
	List<struct vshape> vdata_list;
	for (i = 0; i < map_hedges.size(); i++) {
		for (j = 0; j < map_hedges.size(); j++) {
			if (i == j)
				continue;
			if (map_hedges[i]->b !=
					map_hedges[j]->a)
				continue;
			if (map_hedges[i]->site !=
					map_hedges[j]->site)
				continue;
			int a, b1, b2;
			struct vshape v;
			/* star topology */
			a = map_hedges[i]->b;
			b1 = map_hedges[i]->a;
			b2 = map_hedges[j]->b;
			v.e1 = i;
			v.e2 = j;
			v.site = map_hedges[i]->site;
			v.area.position = vertices[a];
			v.area.expand_to(vertices[b1] + Vector3(0, 1, 0));
			v.area.expand_to(vertices[b2] + Vector3(0, -1, 0));
			v.instance = -1;
			v.depth1 = map_hedges[v.e1]->depth;
			v.depth2 = map_hedges[v.e2]->depth;
			Vector3 p1 = vertices[map_hedges[v.e1]->a];
			Vector3 p2 = vertices[map_hedges[v.e1]->b];
			Vector3 p3 = vertices[map_hedges[v.e2]->b];
			p1 = (p2 + (p1 - p2) * 0.5f).snapped(Vector3(4.0f, 0.1f, 4.0f));
			p3 = (p2 + (p3 - p2) * 0.5f).snapped(Vector3(4.0f, 0.1f, 4.0f));
			p2 = p2.snapped(Vector3(4.0f, 0.1f, 4.0f));
			v.p1 = p1;
			v.p2 = p2;
			v.p3 = p3;
			/* add v-shape only if we can actually generate it */
			if (v.p1.distance_squared_to(v.p2) > 2.0f &&
					v.p2.distance_squared_to(v.p3) > 2.0f &&
					v.p1.distance_squared_to(v.p3) > 2.0f)
				vdata_list.push_back(v);
		}
	}
	vshapes.resize(vdata_list.size());
	for (i = 0; i < vdata_list.size(); i++)
		vshapes.write()[i] = vdata_list[i];
	for (i = 0; i < vshapes.size(); i++) {
		for (j = 0; j < vshapes.size(); j++) {
			if (i == j)
				continue;
			if (vshapes[i].e1 == vshapes[j].e1)
				vshapes.write()[j].p1 = vshapes[i].p1;
			if (vshapes[i].e2 == vshapes[j].e1)
				vshapes.write()[j].p1 = vshapes[i].p3;
			if (vshapes[i].e1 == vshapes[j].e2)
				vshapes.write()[j].p3 = vshapes[i].p1;
			if (vshapes[i].e2 == vshapes[j].e2)
				vshapes.write()[j].p3 = vshapes[i].p3;
		}
	}

	for (i = 0; i < vshapes.size(); i++) {
		const struct vshape &v = vshapes[i];
		assert(map_hedges[v.e1]->site == map_hedges[v.e2]->site);
		assert(v.e1 >= 0 && v.e2 >= 0 && v.e1 != v.e2);
		int e1a = map_hedges[vshapes[i].e1]->a;
		int e1b = map_hedges[vshapes[i].e1]->b;
		int e2a = map_hedges[vshapes[i].e2]->a;
		int e2b = map_hedges[vshapes[i].e2]->b;
		printf("vshape %d: %d: %d: %f %f %f -> %d: %f %f %f -> %d: %d: %f %f %f -> %d: %f %f %f\n",
				i,
				vshapes[i].e1,
				e1a,
				vertices[e1a].x,
				vertices[e1a].y,
				vertices[e1a].z,
				e1b,
				vertices[e1b].x,
				vertices[e1b].y,
				vertices[e1b].z,
				vshapes[i].e2,
				e2a,
				vertices[e2a].x,
				vertices[e2a].y,
				vertices[e2a].z,
				e2b,
				vertices[e2b].x,
				vertices[e2b].y,
				vertices[e2b].z
		      );
	}
}

void RoadGrid::sort_angle(Vector<int> &sort_data)
{
	struct comparator {
		Vector3 *vertices;
		bool operator()(int a, int b) const {
			Vector3 p1 = vertices[a];
			Vector3 p2 = vertices[b];
			Vector2 rp1(p1.x, p1.z);
			Vector2 rp2(p2.x, p2.z);
			return rp1.angle() < rp2.angle();
		}
	};
	SortArray<int, struct comparator> sorter;
	sorter.compare.vertices = vertices.write().ptr();
	sorter.sort(sort_data.ptrw(), sort_data.size());
}

void RoadGrid::generate_3d_vertices(Ref<Curve> curve, Ref<FastNoiseLite> noise)
{
	int i, j;
	Vector<float> diagram_vertex_heights;
	diagram_vertex_heights.resize(diagram_vertices.size());
	for (i = 0; i < diagram_vertices.size(); i++) {
		const Vector2 &v = diagram_vertices[i];
		float n = noise->get_noise_2d(v.x, v.y);
		float t = (n + 1.0f) * 0.5f;
		float d = MAX(1.0f, curve->interpolate_baked(t));
		d = CLAMP(d, 1.0f, 30.0f);
		diagram_vertex_heights.write[i] = d;
	}
	for (j = 0; j < 3; j++) {
		for (i = 0; i < map_hedges.size(); i++) {
			int x1 = map_hedges[i]->a;
			int x2 = map_hedges[i]->b;
			float xd = map_hedges[i]->length;
			float dh = fabsf(diagram_vertex_heights[x2] - diagram_vertex_heights[x1]);
			if (fabsf(dh / xd) > 0.01f)
				diagram_vertex_heights.write[x2] = diagram_vertex_heights[x1] + dh / fabsf(dh) * 0.01f * xd;
		}
	}
	vertices.resize(get_diagram_vertex_count());
	for (i = 0; i < vertices.size(); i++) {
		vertices.write()[i].x = diagram_vertices[i].x;
		vertices.write()[i].y = diagram_vertex_heights[i];
		vertices.write()[i].z = diagram_vertices[i].y;
	}
}

void RoadGrid::generate_building_positions()
{
	int i;
	for (i = 0; i < map_sites.size(); i++)
		generate_site_building_positions(&map_sites[i]);
}

void RoadGrid::generate_site_building_positions(const struct map_site *site)
{
	Vector<Vector2> border;
	Vector3 center_point;
}
int RoadGrid::get_site_from_point(int x, int z)
{
	int i;
	for (i = 0; i < map_sites.size(); i++)
		if (map_sites[i].rect.has_point(Vector2i(x, z)))
			if (Geometry::is_point_in_polygon(Vector2((float)x, (float)z), map_sites[i].polygon))
				return i;
	return -1;
}

static String var2str(const Variant &data)
{
	String s;
	VariantWriter::write_to_string(data, s);
	return s;
}
template <class T>
static Array avar2str(const Vector<T> &data)
{
	Array pdata;
	int i;
	pdata.resize(data.size());
	for (i = 0; i < data.size(); i++)
		pdata[i] = var2str(data[i]);
	return pdata;
}
static Dictionary half_edge2dict(const struct half_edge *he)
{
	Dictionary ret;
	ret["a"] = he->a;
	ret["b"] = he->b;
	ret["site"] = he->site;
	ret["depth"] = he->depth;
	ret["length"] = he->length;
	return ret;
}
static Array rect2i_array(const Rect2i &rect)
{
	Array tmp;
	tmp.resize(4);
	tmp[0] = rect.position[0];
	tmp[1] = rect.position[1];
	tmp[2] = rect.size[0];
	tmp[3] = rect.size[1];
	return tmp;
}
static Dictionary map_site2dict(const struct map_site *ms)
{
	int i;
	Dictionary ret;
	Array hedges;
	ret["index"] = ms->index;
	ret["pos"] = var2str(ms->pos);
	ret["vertices"] = avar2str(ms->vertices);
	ret["polygon"] = avar2str(ms->polygon);
	ret["vertices_ind"] = avar2str(ms->vertices_ind);
	ret["polygon_ind"] = avar2str(ms->polygon_ind);
	ret["site_type"] = ms->site_type;
	ret["cluster"] = ms->cluster;
	hedges.resize(ms->hedges.size());
	for (i = 0; i < ms->hedges.size(); i++)
		hedges[i] = half_edge2dict(&ms->hedges[i]);
	ret["hedges"] = hedges;
	ret["rect"] = rect2i_array(ms->rect);
	ret["avg_height"] = ms->avg_height;
	return ret;
}
static Dictionary vshape2dict(const struct vshape *v)
{
	Dictionary ret;
	ret["area"] = var2str(v->area);
	ret["instance"] = v->instance;
	ret["e1"] = v->e1;
	ret["e2"] = v->e2;
	ret["site"] = v->site;
	ret["p1"] = var2str(v->p1);
	ret["p2"] = var2str(v->p2);
	ret["p3"] = var2str(v->p3);
	ret["depth1"] = v->depth1;
	ret["depth2"] = v->depth2;
	return ret;
}
void RoadGrid::save_json(const String &path)
{
	int i;
	String vars;
	FileAccess *f;
	Dictionary to_json;
	/* Clusters */
	Array save_clusters;
	/* save clusters */
	save_clusters.resize(clusters.size());
	for (i = 0; i < clusters.size(); i++) {
		Dictionary cluster;
		cluster["pos_x"] = clusters[i].c.x;
		cluster["pos_y"] = clusters[i].c.y;
		cluster["radius"] = clusters[i].r;
		save_clusters[i] = cluster;
	}
	to_json["clusters"] = save_clusters;
	to_json["bounds"] = var2str(bounds);
	to_json["diagram_vertices"] = avar2str(diagram_vertices);
	Array msites, mvshapes;
	msites.resize(map_sites.size());
	for (i = 0; i < map_sites.size(); i++)
		msites[i] = map_site2dict(&map_sites[i]);
	to_json["map_sites"] = msites;
	to_json["vertices"] = var2str(vertices);
	mvshapes.resize(vshapes.size());
	for (i = 0; i < vshapes.size(); i++) {
		const struct vshape *v = &(vshapes.read()[i]);
		mvshapes[i] = vshape2dict(v);
	}
	to_json["vshapes"] = mvshapes;

	String json = JSON::print(to_json, "\t");
	f = FileAccess::open(path, FileAccess::WRITE);
	if (f) {
		f->store_string(json);
		f->close();
	}
}
PoolVector<Vector3> RoadGrid::get_site_border(int site)
{
	const struct map_site &msite = map_sites[site];
	List<struct vshape *> site_vshapes;
	List<struct vshape *>::Element *e;
	PoolVector<Vector3> ret;
	int i, j;
	for (i = 0; i < msite.polygon_ind.size(); i++) {
		int p1 = i;
		int p2 = (i + 1) % msite.polygon_ind.size();
		int p3 = (i + 2) % msite.polygon_ind.size();
		for (j = 0; j < vshapes.size(); j++) {
			struct vshape &v = vshapes.write()[j];
			if (v.site != site)
				continue;
			struct half_edge *hedge1 = map_hedges[v.e1];
			struct half_edge *hedge2 = map_hedges[v.e2];
			if (hedge1->a != p1 ||
					hedge1->b != p2 || hedge2->b != p3)
				continue;
			site_vshapes.push_back(&v);
		}
	}
	ret.resize(site_vshapes.size());
	int count = 0;
	for (e = site_vshapes.front(); e; e = e->next()) {
		struct vshape *pv = e->get();
		float l = pv->curve3->get_baked_length();
		Vector3 bp = pv->curve3->interpolate_baked(l * 0.5f) + pv->p2;
		ret.write()[count++] = bp;
	}
	printf("polygon count %d border count %d\n",
			msite.polygon_ind.size(), ret.size());
	assert(msite.polygon_ind.size() == ret.size());
	return ret;
}

