17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 09:49:19 +02:00

feat(roads): junctions, height above the ground and rounded profile following the terrain

This commit is contained in:
2026-10-03 20:28:37 +02:00
parent e4083d507f
commit daeed40f15
13 changed files with 1963 additions and 103 deletions

View File

@@ -231,11 +231,13 @@ namespace
};
// appends triangles of a shape node which overlap specified XZ rectangle
void gather_shape_triangles(scene::shape_node const &Shape, glm::dvec2 const &Min, glm::dvec2 const &Max, std::vector<world_triangle> &Out)
void gather_shape_triangles(scene::shape_node const &Shape, glm::dvec2 const &Min, glm::dvec2 const &Max, std::vector<world_triangle> &Out, bool const Skiproads = false)
{
auto const &data = Shape.data();
if (editor_orthophoto::owns(data.geometry))
return; // the orthophoto laid over the ground isn't ground itself
if (Skiproads && owned_shapes::owns(data.geometry))
return; // neither are the roads, for the ones which ask where to put a road
if (data.area.radius >= 0.0f)
{
double const r = data.area.radius;
@@ -275,7 +277,7 @@ namespace
// ground triangles overlapping an XZ rectangle (Min/Max are x,z). shapes hold the (legacy) terrain,
// model instances at least ModelRadius large (if ModelsAsGround) the terrain tiles
void gather_ground_triangles(glm::dvec2 const &Min, glm::dvec2 const &Max, bool const ModelsAsGround, float const ModelRadius, std::vector<world_triangle> &Out)
void gather_ground_triangles(glm::dvec2 const &Min, glm::dvec2 const &Max, bool const ModelsAsGround, float const ModelRadius, std::vector<world_triangle> &Out, bool const Skiproads = false)
{
glm::dvec2 const center = (Min + Max) * 0.5;
float const radius = static_cast<float>(glm::length(Max - Min) * 0.5);
@@ -283,7 +285,7 @@ namespace
for (auto *section : sections)
{
for (auto const &shape : section->m_shapes)
gather_shape_triangles(shape, Min, Max, Out);
gather_shape_triangles(shape, Min, Max, Out, Skiproads);
for (auto &cell : section->m_cells)
{
double const r = cell.m_area.radius;
@@ -349,6 +351,71 @@ editor_mode::editor_mode() {
});
}
std::vector<double> editor_mode::ground_heights(std::vector<glm::dvec3> const &Points, bool const Fresh)
{
std::vector<double> heights;
heights.reserve(Points.size());
for (auto const &point : Points)
heights.push_back(point.y);
if (Points.empty() || simulation::Region == nullptr)
return heights;
glm::dvec2 bmin{Points.front().x, Points.front().z};
glm::dvec2 bmax{bmin};
for (auto const &point : Points)
{
bmin = glm::min(bmin, glm::dvec2{point.x, point.z});
bmax = glm::max(bmax, glm::dvec2{point.x, point.z});
}
// the road tools ask about the same place frame after frame, so the ground is gathered with room to spare and kept for a moment
struct ground_cache
{
glm::dvec2 min{0.0};
glm::dvec2 max{0.0};
std::unique_ptr<triangle_grid> grid;
double time{0.0};
};
static ground_cache cache;
double constexpr cache_margin = 60.0;
double constexpr cache_lifetime = 5.0;
double const now = ImGui::GetTime();
if (Fresh || cache.grid == nullptr || now < cache.time || now - cache.time > cache_lifetime || bmin.x < cache.min.x || bmin.y < cache.min.y || bmax.x > cache.max.x || bmax.y > cache.max.y)
{
cache.min = bmin - glm::dvec2{cache_margin};
cache.max = bmax + glm::dvec2{cache_margin};
std::vector<world_triangle> triangles;
// the same ground as the area fill uses, terrain tile models included
gather_ground_triangles(cache.min, cache.max, true, 50.0f, triangles, true);
cache.grid = std::make_unique<triangle_grid>(std::move(triangles), cache.min, cache.max);
cache.time = now;
}
// surfaces much higher than the point are something it's under, rather than the ground
double constexpr height_tolerance = 50.0;
auto const terrains = active_terrains();
for (std::size_t i = 0; i < Points.size(); ++i)
{
auto const &p = Points[i];
double const ceiling = p.y + height_tolerance;
double y = 0.0;
bool found = cache.grid->height_at(p.x, p.z, ceiling, y);
for (editor_terrain *terrain : terrains)
{
if (!terrain->contains(p.x, p.z))
continue;
double const h = terrain->height_at(p.x, p.z);
if (h <= ceiling && (!found || h > y))
{
y = h;
found = true;
}
}
if (found)
heights[i] = y;
}
return heights;
}
editor_ui *editor_mode::ui() const
{
return static_cast<editor_ui *>(m_userinterface.get());