diff --git a/src/modules/stream/contours.cpp b/src/modules/stream/contours.cpp index 9f37417..4e8e55a 100644 --- a/src/modules/stream/contours.cpp +++ b/src/modules/stream/contours.cpp @@ -1,4 +1,8 @@ +#undef NDEBUG +#include #include +#include +#include "wedge.h" #include "contours.h" Contours *Contours::singleton = nullptr; @@ -11,6 +15,7 @@ Contours *Contours::get_singleton() } Contours::Contours() + : dbg(nullptr) { } @@ -27,4 +32,247 @@ bool Contours::is_in_closed_contour(const struct wedge *w) if (wedge_contours[i][j] == w) return true; return false; -} \ No newline at end of file +} + +static Vector3 tangent(const Vector3 &v) +{ + Vector2 rv = Vector2(v.x, v.z).tangent(); + return Vector3(rv.x, v.y, rv.y); +} +static Vector3 normal(const Vector3 &v) +{ + Vector3 rv = tangent(v); + rv.y = 0.0f; + return rv.normalized(); +} + +void Contours::build() +{ + int i, j; + contours.clear(); + for (i = 0; i < (int)wedge_contours.size(); i++) { + struct main_contour mc; + for (j = 0; j < (int)wedge_contours[i].size(); j++) { + struct wedge *w = wedge_contours[i][j]; + struct contour_wedge cw; + Vector3 d1 = (w->p[1] - w->p[0]).normalized(); + Vector3 n1 = normal(d1); + Vector3 d2 = (w->p[2] - w->p[1]).normalized(); + Vector3 n2 = normal(d2); + Vector3 m1 = n1 * (w->width1); + Vector3 m2 = n2 * (w->width2); + Vector3 dx = (d1 + d2).normalized(); + Vector3 f1 = w->p[1] + m1; + Vector3 f2 = w->p[1] + m2; + Vector3 q, r; + Geometry::get_closest_points_between_segments( + w->p[0] + m1, f1, f2, w->p[2] + m2, q, r); + r = q.linear_interpolate(r, 0.5f); + cw.p[0] = w->p[0] + m1; + cw.p[1] = r; + cw.p[2] = w->p[2] + m2; + if (mc.aabb.size.is_equal_approx(Vector3())) + mc.aabb.position = cw.p[0]; + else + mc.aabb.expand_to(cw.p[0]); + mc.aabb.expand_to(cw.p[1]); + mc.aabb.expand_to(cw.p[2]); + mc.points.push_back(cw.p[0]); + mc.points.push_back(cw.p[1]); + cw.wedge = w; + mc.contour_wedges.push_back(cw); + } + contours.push_back(mc); + } + polygons.clear(); + for (i = 0; i < (int)contours.size(); i++) + polygons.push_back({ contours[i].points, contours[i].aabb }); + List polygon_queue; + List polygon_output; + for (i = 0; i < (int)polygons.size(); i++) + polygon_queue.push_back(polygons[i]); + polygons.clear(); + List::Element *e = polygon_queue.front(); + while (e) { + struct polygon item = e->get(); + print_line("queue: " + itos(polygon_queue.size())); + polygon_queue.pop_front(); + float area = item.area(); + if (area > 120.0f * 120.0f && item.aabb.size.x > 10.0f && + item.aabb.size.z > 10.0f) { + std::pair polys = + item.split(); + if (polys.first.area() < 10.0f || + polys.second.area() < 10.0f) { + polygon_output.push_back(item); + } else { + polygon_queue.push_back(polys.first); + polygon_queue.push_back(polys.second); + } + } else + polygon_output.push_back(item); + e = polygon_queue.front(); + } + polygons.reserve(polygon_output.size()); + e = polygon_output.front(); + while (e) { + polygons.push_back(e->get()); + e = e->next(); + } +} + +void Contours::debug() +{ + int i, j; + if (!dbg) { + dbg = memnew(ImmediateGeometry); + SceneTree::get_singleton()->get_current_scene()->call_deferred( + "add_child", dbg); + if (!imm_mat.is_valid()) { + imm_mat.instance(); + imm_mat->set_flag( + SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, + true); + imm_mat->set_flag( + SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); + imm_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + } + dbg->set_material_override(imm_mat); + } + dbg->clear(); + dbg->begin(Mesh::PRIMITIVE_LINES); + dbg->set_color(Color(1, 1, 0, 1)); + for (i = 0; i < (int)wedge_contours.size(); i++) { + for (j = 0; j < (int)wedge_contours[i].size(); j++) { + dbg->add_vertex(wedge_contours[i][j]->p[0] + + Vector3(0, 1, 0)); + dbg->add_vertex(wedge_contours[i][j]->p[1] + + Vector3(0, 1, 0)); + dbg->add_vertex(wedge_contours[i][j]->p[1] + + Vector3(0, 1, 0)); + dbg->add_vertex(wedge_contours[i][j]->p[2] + + Vector3(0, 1, 0)); + } + } + dbg->end(); + dbg->begin(Mesh::PRIMITIVE_LINES); + dbg->set_color(Color(1, 1, 0.4f, 1)); + for (i = 0; i < (int)polygons.size(); i++) { + for (j = 0; j < (int)polygons[i].points.size(); j++) { + dbg->add_vertex(polygons[i].points[j] + + Vector3(0, 2, 0)); + dbg->add_vertex( + polygons[i].points[(j + 1) % + polygons[i].points.size()] + + Vector3(0, 2, 0)); + } + } + dbg->end(); +} + +std::pair +Contours::polygon::split() const +{ + int i, j; + float split_polygons_area = 0.0f; + float split_polygons_area_min = 0.0f; + std::pair + split_polygons; + std::vector edges; + for (i = 0; i < (int)points.size(); i++) { + Vector3 p0 = points[i]; + Vector3 p1 = points[(i + 1) % points.size()]; + if (p0.distance_squared_to(p1) > 100 * 100) + edges.push_back(i); + } + if (edges.size() == 0) { + for (i = 0; i < (int)points.size(); i++) { + Vector3 p0 = points[i]; + Vector3 p1 = points[(i + 1) % points.size()]; + edges.push_back(i); + } + } + for (i = 0; i < (int)edges.size(); i++) { + Vector3 p0 = points[edges[i]]; + Vector3 p1 = points[(edges[i] + 1) % points.size()]; + Transform xf = + Transform(Basis(), p0).looking_at(p1, Vector3(0, 1, 0)); + AABB base; + base.position = xf.xform_inv(p0); + base.expand_to(xf.xform_inv(p1)); + for (j = 0; j < (int)points.size(); j++) + base.expand_to(xf.xform_inv(points[j])); + Vector3 mpos0, mpos1; + if (base.size.x > base.size.z) { + mpos0 = base.position + + Vector3(base.size.x, 0, 0) * 0.5f; + mpos1 = mpos0 + Vector3(0, 0, base.size.z); + mpos0 = xf.xform(mpos0); + mpos1 = xf.xform(mpos1); + } else { + mpos0 = base.position + + Vector3(0, 0, base.size.z) * 0.5f; + mpos1 = mpos0 + Vector3(base.size.x, 0, 0); + mpos0 = xf.xform(mpos0); + mpos1 = xf.xform(mpos1); + } + mpos0.y = 0; + mpos1.y == 0; + /* mpos0 is at start of cut */ + + Vector3 n = + (mpos1 - mpos0).cross(Vector3(0, 1, 0)).normalized(); + Plane pl1(mpos0 - n * 1.5f, n); + Plane pl2(mpos0 + n * 1.5f, -n); + Vector pdata; + pdata.resize(points.size()); + memcpy(pdata.ptrw(), points.data(), + points.size() * sizeof(Vector3)); + struct polygon poly1, poly2; + Vector rpdata = Geometry::clip_polygon(pdata, pl1); + poly1.points.resize(rpdata.size()); + memcpy(poly1.points.data(), rpdata.ptr(), + rpdata.size() * sizeof(Vector3)); + poly1.update_aabb(); + rpdata = Geometry::clip_polygon(pdata, pl2); + poly2.points.resize(rpdata.size()); + memcpy(poly2.points.data(), rpdata.ptr(), + rpdata.size() * sizeof(Vector3)); + poly2.update_aabb(); + float area1 = poly1.area(); + float area2 = poly2.area(); + if (area1 <= 4.0f || area2 <= 4.0f) + continue; + float area_min = MIN(area1, area2); + float area = area1 + area2; + if (split_polygons_area_min < area_min && + split_polygons_area < area) { + split_polygons = { poly1, poly2 }; + split_polygons_area_min = area_min; + split_polygons_area = area; + } + } + return split_polygons; +} + +int Contours::polygon::longest_edge() const +{ + return 0; +} + +void Contours::polygon::update_aabb() +{ + aabb = AABB(); + int i; + for (i = 0; i < (int)points.size(); i++) { + if (aabb.is_equal_approx(AABB())) + aabb.position = points[i]; + else + aabb.expand_to(points[i]); + } +} + +float Contours::polygon::area() const +{ + return Geometry::find_polygon_area(points.data(), points.size()); +} diff --git a/src/modules/stream/contours.h b/src/modules/stream/contours.h index bc439bc..55fbdec 100644 --- a/src/modules/stream/contours.h +++ b/src/modules/stream/contours.h @@ -3,13 +3,37 @@ #define CONTOURS_H_ #include +class ImmediateGeometry; struct Contours { + struct contour_wedge { + Vector3 p[3]; + struct wedge *wedge; + }; + struct main_contour { + std::vector contour_wedges; + std::vector points; + AABB aabb; + }; + struct polygon { + std::vector points; + AABB aabb; + std::pair split() const; + float area() const; + int longest_edge() const; + void update_aabb(); + }; + void build(); + ImmediateGeometry *dbg; + Ref imm_mat; std::vector > wedge_contours; + std::vector contours; + std::vector polygons; static Contours *singleton; static Contours *get_singleton(); Contours(); virtual ~Contours(); bool is_in_closed_contour(const struct wedge *w); + void debug(); }; #endif // CONTOURS_H_ \ No newline at end of file diff --git a/src/modules/stream/road_processing.cpp b/src/modules/stream/road_processing.cpp index 13ccb26..0354bc3 100644 --- a/src/modules/stream/road_processing.cpp +++ b/src/modules/stream/road_processing.cpp @@ -22,21 +22,9 @@ #include "road_lines_data.h" #include "buildings_data.h" #include "contours.h" +#include "wedge.h" #include "road_processing.h" -struct side_ref { - String line_key; - int edge; - int side; // left = 0, right = 1 -}; -struct wedge { - Vector3 p[3]; - Vector3 y[3]; - int width1, width2; - struct side_ref side1_ref, side2_ref; - bool acute; -}; - class DebugGeo : public ImmediateGeometry { Ref imm_mat; int vertex_count; @@ -1245,6 +1233,8 @@ out_skip_end:; if (base >= (int)wedges_ref.size()) break; } + contours->build(); + contours->debug(); } ~RoadLinesProcessing() { diff --git a/src/modules/stream/wedge.h b/src/modules/stream/wedge.h new file mode 100644 index 0000000..8fd29dd --- /dev/null +++ b/src/modules/stream/wedge.h @@ -0,0 +1,20 @@ +/* ~/godot-projects/streaming_world/src/modules/stream/wedge.h */ +#ifndef WEDGE_H_ +#define WEDGE_H_ +#include +#include + +struct side_ref { + String line_key; + int edge; + int side; // left = 0, right = 1 +}; +struct wedge { + Vector3 p[3]; + Vector3 y[3]; + int width1, width2; + struct side_ref side1_ref, side2_ref; + bool acute; +}; + +#endif // WEDGE_H_ \ No newline at end of file