720 lines
21 KiB
C++
720 lines
21 KiB
C++
#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;
|
|
}
|
|
|