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

refactor(editor): shared plan geometry and formatting helpers

This commit is contained in:
maj00r
2026-10-04 00:33:44 +02:00
parent 8778353b22
commit e5c91d8a1a
10 changed files with 392 additions and 487 deletions

View File

@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "editor/editorInfra.hpp"
#include "editor/editorGeometry.hpp"
#include "world/Track.h"
#include <algorithm>
@@ -23,50 +24,21 @@ namespace infra
namespace
{
using geometry::bezier;
using geometry::plan_distance;
using geometry::plan_of;
int const kSteps{128};
struct curve
{
glm::dvec3 p0, p1, p2, p3;
};
curve curve_of(segment_data const &Path)
{
auto const &start{Path.points[segment_data::point::start]};
auto const &end{Path.points[segment_data::point::end]};
auto const &control1{Path.points[segment_data::point::control1]};
auto const &control2{Path.points[segment_data::point::control2]};
if (control1 == glm::dvec3{} && control2 == glm::dvec3{})
return {start, start + (end - start) / 3.0, end + (start - end) / 3.0, end};
return {start, start + control1, end + control2, end};
}
glm::dvec3 point(curve const &Curve, double const T)
{
auto const u{1.0 - T};
return Curve.p0 * (u * u * u) + Curve.p1 * (3.0 * u * u * T) + Curve.p2 * (3.0 * u * T * T) + Curve.p3 * (T * T * T);
}
glm::dvec3 derivative(curve const &Curve, double const T)
{
auto const u{1.0 - T};
return (Curve.p1 - Curve.p0) * (3.0 * u * u) + (Curve.p2 - Curve.p1) * (6.0 * u * T) + (Curve.p3 - Curve.p2) * (3.0 * T * T);
}
double plan(glm::dvec3 const &A, glm::dvec3 const &B)
{
return std::hypot(A.x - B.x, A.z - B.z);
}
// arc length in the plan at the evenly spread parameters
std::array<double, kSteps + 1> lengths(curve const &Curve)
std::array<double, kSteps + 1> lengths(bezier const &Curve)
{
std::array<double, kSteps + 1> result{};
auto previous{Curve.p0};
for (int i = 1; i <= kSteps; ++i)
{
auto const next{point(Curve, static_cast<double>(i) / kSteps)};
result[i] = result[i - 1] + plan(previous, next);
auto const next{Curve.point(static_cast<double>(i) / kSteps)};
result[i] = result[i - 1] + plan_distance(previous, next);
previous = next;
}
return result;
@@ -92,9 +64,9 @@ double length_at(std::array<double, kSteps + 1> const &Lengths, double const T)
return Lengths[index] + (Lengths[index + 1] - Lengths[index]) * (position - index);
}
glm::dvec2 plan_direction(curve const &Curve, double const T)
glm::dvec2 plan_direction(bezier const &Curve, double const T)
{
auto tangent{derivative(Curve, T)};
auto tangent{Curve.first(T)};
glm::dvec2 result{tangent.x, tangent.z};
if (glm::length(result) < 1e-9)
result = {Curve.p3.x - Curve.p0.x, Curve.p3.z - Curve.p0.z};
@@ -144,27 +116,27 @@ std::vector<category> const &categories()
double plan_length(segment_data const &Path)
{
return lengths(curve_of(Path)).back();
return lengths(bezier{Path}).back();
}
std::vector<glm::dvec3> outline(segment_data const &Path, double const Step)
{
auto const shape{curve_of(Path)};
bezier const shape{Path};
// the speed along the curve doesn't exceed three times the longest leg of the control polygon
auto const leg{std::max({plan(shape.p0, shape.p1), plan(shape.p1, shape.p2), plan(shape.p2, shape.p3)})};
auto const leg{std::max({plan_distance(shape.p0, shape.p1), plan_distance(shape.p1, shape.p2), plan_distance(shape.p2, shape.p3)})};
auto const count{std::clamp(static_cast<int>(std::ceil(3.0 * leg / std::max(Step, 0.1))), 1, 4096)};
std::vector<glm::dvec3> result;
result.reserve(count + 1);
for (int i = 0; i <= count; ++i)
result.push_back(point(shape, static_cast<double>(i) / count));
result.push_back(shape.point(static_cast<double>(i) / count));
return result;
}
frame frame_at(segment_data const &Path, double const S)
{
auto const shape{curve_of(Path)};
bezier const shape{Path};
auto const t{parameter(lengths(shape), S)};
return {point(shape, t), plan_direction(shape, t)};
return {shape.point(t), plan_direction(shape, t)};
}
frame frame_at(station const &Station)
@@ -176,9 +148,9 @@ frame frame_at(station const &Station)
double project(segment_data const &Path, glm::dvec3 const &Point, double &S, bool &Interior)
{
auto const shape{curve_of(Path)};
bezier const shape{Path};
auto const table{lengths(shape)};
auto const distance = [&](double const T) { return plan(point(shape, T), Point); };
auto const distance = [&](double const T) { return plan_distance(shape.point(T), Point); };
auto best{0};
auto bestdistance{distance(0.0)};
for (int i = 1; i <= kSteps; ++i)
@@ -256,7 +228,7 @@ anchor make_anchor(station const &At, glm::dvec3 const &Point)
result.at = At;
auto const axis{frame_at(At)};
glm::dvec2 const side{axis.forward.y, -axis.forward.x};
result.offset = glm::dot(glm::dvec2{Point.x - axis.point.x, Point.z - axis.point.z}, side);
result.offset = glm::dot(plan_of(Point - axis.point), side);
result.height = Point.y - axis.point.y;
result.foot = axis.point;
if (At.track != nullptr && At.path >= 0 && At.path < static_cast<int>(At.track->m_paths.size()))