17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-08 19:52:47 +01:00

refactor(editor): the structure gauge is a tool of its own

The first step of taking the tools out of editor_mode: a tool keeps its
own state and reaches the editor through editor_services, the few things
it needs from it, instead of through every member of the editor. The
editor holds its tools in a list for the hooks they share: a deleted
node is forgotten by all of them in one place, and a self-test command
the editor doesn't know goes to each of them.

The gauge moves with its state, its window and its self-test command;
the ImGui ids and the texts stay the same, and the self-test gives the
same hits on the test scenery as before.
This commit is contained in:
maj00r
2026-10-21 09:00:59 +02:00
parent a168e2ccfc
commit 3c9c90b468
9 changed files with 232 additions and 123 deletions

View File

@@ -8,7 +8,8 @@ http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "application/editormode.h"
#include "application/editormodegauge.h"
#include "editor/editorTrack.hpp"
#include "application/editoruilayer.h"
#include "editor/editorFormat.hpp"
#include "editor/editorGauge.hpp"
@@ -326,7 +327,7 @@ template <typename Visitor> void visit_triangles(TSubModel *Submodel, glm::dmat4
}
// the triangle enters the gauge when any point of a grid spread over it does; the deepest such point goes to the hit
void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C, editor_mode::gauge_hit &Hit)
void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C, gauge_tool::gauge_hit &Hit)
{
auto const middle{(A + B + C) / 3.0};
if (false == Space.close(middle, std::max({glm::distance(middle, A), glm::distance(middle, B), glm::distance(middle, C)})))
@@ -353,24 +354,24 @@ void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const
}
// the deepest place of the model in the gauge, added to the hits when it enters it
void scan_model(corridor const &Space, TAnimModel &Instance, std::vector<editor_mode::gauge_hit> &Hits)
void scan_model(corridor const &Space, TAnimModel &Instance, std::vector<gauge_tool::gauge_hit> &Hits)
{
if (false == Instance.visible() || Instance.Model() == nullptr || Instance.Model()->GetSMRoot() == nullptr)
return;
if (false == Space.nearby(Instance.location(), Instance.radius()))
return;
editor_mode::gauge_hit hit{Instance.name(), Instance.location()};
gauge_tool::gauge_hit hit{Instance.name(), Instance.location()};
visit_triangles(Instance.Model()->GetSMRoot(), placement(Instance), [&](glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C) { scan_triangle(Space, A, B, C, hit); });
if (hit.depth > 0.0)
Hits.push_back(std::move(hit));
}
// the same for the copies of a model laid along a curve
void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector<editor_mode::gauge_hit> &Hits)
void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector<gauge_tool::gauge_hit> &Hits)
{
if (Sweep.m_editorremoved || false == Space.nearby(Sweep.location(), Sweep.radius()))
return;
editor_mode::gauge_hit hit{Sweep.name(), Sweep.location()};
gauge_tool::gauge_hit hit{Sweep.name(), Sweep.location()};
for (auto const &shape : Sweep.create_shapes())
{
auto const &vertices{shape.data().vertices};
@@ -381,13 +382,13 @@ void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector<editor_mod
Hits.push_back(std::move(hit));
}
void sort_hits(std::vector<editor_mode::gauge_hit> &Hits)
void sort_hits(std::vector<gauge_tool::gauge_hit> &Hits)
{
std::sort(Hits.begin(), Hits.end(), [](auto const &Left, auto const &Right) { return Left.depth > Right.depth; });
}
// the models entering the gauge, the deepest first
void scan_models(corridor const &Space, std::vector<editor_mode::gauge_hit> &Hits)
void scan_models(corridor const &Space, std::vector<gauge_tool::gauge_hit> &Hits)
{
for (auto *instance : simulation::Instances.sequence())
if (instance != nullptr)
@@ -550,7 +551,7 @@ struct gauge_scan
std::chrono::steady_clock::time_point started;
};
void editor_mode::gauge_load()
void gauge_tool::gauge_load()
{
if (m_gauge.profiles.empty())
m_gauge.profiles = gauge::load_profiles(gauge_file);
@@ -568,18 +569,18 @@ void editor_mode::gauge_load()
}
}
gauge::choice editor_mode::gauge_choice() const
gauge::choice gauge_tool::gauge_choice() const
{
auto const pick{[&](int const Index) { return Index >= 0 ? &m_gauge.profiles[Index] : nullptr; }};
return {pick(m_gauge.profile), pick(m_gauge.road)};
}
std::vector<editor_mode::gauge_hit> const &editor_mode::gauge_hits() const
std::vector<gauge_tool::gauge_hit> const &gauge_tool::gauge_hits() const
{
return m_gauge.map.scanned ? m_gauge.map.hits : m_gauge.line.hits;
}
void editor_mode::update_gauge()
void gauge_tool::update()
{
if (m_gauge.scan)
step_gauge_map();
@@ -590,9 +591,9 @@ void editor_mode::update_gauge()
m_gauge.published = false;
return;
}
auto *track{m_gauge.enabled ? selected_track() : nullptr};
auto *track{m_gauge.enabled ? m_services.selected_track() : nullptr};
// the geometry is rescanned once the edit ends
if (ImGui::IsMouseDown(0) || m_track_gizmo_using || m_dragging)
if (ImGui::IsMouseDown(0) || m_services.track_editing())
m_gauge.pending = true;
else if (track == nullptr)
{
@@ -603,19 +604,19 @@ void editor_mode::update_gauge()
m_gauge.published = false;
}
}
else if (track != m_gauge.track || m_history.size() != m_gauge.history || m_gauge.pending)
else if (track != m_gauge.track || m_services.history_size() != m_gauge.history || m_gauge.pending)
{
m_gauge.track = track;
m_gauge.history = m_history.size();
m_gauge.history = m_services.history_size();
m_gauge.pending = false;
scan_gauge(*track);
m_gauge.published = false;
}
if (false == m_gauge.published || glm::distance(Camera.Pos, EditorOverlay.origin) > gauge_origin_range)
if (false == m_gauge.published || glm::distance(m_services.camera_position(), EditorOverlay.origin) > gauge_origin_range)
gauge_publish();
}
void editor_mode::scan_gauge(TTrack &Track)
void gauge_tool::scan_gauge(TTrack &Track)
{
gauge_load();
m_gauge.line = {};
@@ -631,7 +632,7 @@ void editor_mode::scan_gauge(TTrack &Track)
m_gauge.current = -1;
}
void editor_mode::scan_gauge_map()
void gauge_tool::scan_gauge_map()
{
gauge_load();
auto scan{std::make_shared<gauge_scan>()};
@@ -644,7 +645,7 @@ void editor_mode::scan_gauge_map()
scan->space.emplace(scan->lines);
m_gauge.map = {};
m_gauge.map.scanned = true;
m_gauge.map.history = m_history.size();
m_gauge.map.history = m_services.history_size();
auto const name{[](gauge::profile const *Profile) { return Profile != nullptr ? Profile->name : std::string{"-"}; }};
m_gauge.map.profile = name(chosen.railway) + ", " + name(chosen.road);
m_gauge.current = -1;
@@ -652,7 +653,7 @@ void editor_mode::scan_gauge_map()
m_gauge.scan = std::move(scan);
}
void editor_mode::step_gauge_map()
void gauge_tool::step_gauge_map()
{
auto &scan{*m_gauge.scan};
auto const &instances{simulation::Instances.sequence()};
@@ -675,7 +676,7 @@ void editor_mode::step_gauge_map()
finish_gauge_map();
}
void editor_mode::finish_gauge_map()
void gauge_tool::finish_gauge_map()
{
auto const scan{std::move(m_gauge.scan)};
auto &hits{m_gauge.map.hits};
@@ -690,11 +691,11 @@ void editor_mode::finish_gauge_map()
gauge_focus(0);
}
void editor_mode::gauge_publish()
void gauge_tool::gauge_publish()
{
m_gauge.published = true;
EditorOverlay.clear();
EditorOverlay.origin = Camera.Pos;
EditorOverlay.origin = m_services.camera_position();
auto const batch{[](glm::vec4 const &Color, unsigned int const Type, std::vector<glm::dvec3> const &Points) {
gfx::editor_overlay::batch result{Color, Type};
result.points.reserve(Points.size());
@@ -717,7 +718,7 @@ void editor_mode::gauge_publish()
batch({0.2f, 1.0f, 0.3f, 0.5f}, GL_LINES, m_gauge.spot.edges)};
}
void editor_mode::gauge_focus(int const Index)
void gauge_tool::gauge_focus(int const Index)
{
auto const &hits{gauge_hits()};
if (hits.empty())
@@ -729,12 +730,12 @@ void editor_mode::gauge_focus(int const Index)
// along the track, tangent to the gauge at the height of the place, from the end nearer to the camera
glm::dvec3 look{hit.direction.x, 0.0, hit.direction.y};
look = glm::length(look) > 1e-6 ? glm::normalize(look) : glm::dvec3(0.0, 0.0, 1.0);
if (glm::dot(Camera.Pos - hit.point, look) > 0.0)
if (glm::dot(m_services.camera_position() - hit.point, look) > 0.0)
look = -look;
fly_to(hit.point, look, gauge_view_distance);
m_services.fly_to(hit.point, look, gauge_view_distance);
}
void editor_mode::gauge_spot(gauge_hit const &Hit)
void gauge_tool::gauge_spot(gauge_hit const &Hit)
{
m_gauge.spot = {};
auto const &paths{simulation::Paths.sequence()};
@@ -751,7 +752,7 @@ void editor_mode::gauge_spot(gauge_hit const &Hit)
build_tunnel(*line, m_gauge.spot.surface, m_gauge.spot.edges);
}
void editor_mode::render_gauge_window()
void gauge_tool::render_windows()
{
if (false == m_gauge.open)
return;
@@ -798,7 +799,7 @@ void editor_mode::render_gauge_window()
m_gauge.current = -1;
m_gauge.published = false;
}
else if (m_gauge.map.history != m_history.size())
else if (m_gauge.map.history != m_services.history_size())
ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.3f, 1.0f), STR_C("The scenery changed since the scan (%s)"), m_gauge.map.profile.c_str());
}
render_gauge_hits();
@@ -809,7 +810,7 @@ void editor_mode::render_gauge_window()
ImGui::End();
}
void editor_mode::render_gauge_hits()
void gauge_tool::render_gauge_hits()
{
auto const &hits{gauge_hits()};
if (false == m_gauge.map.scanned && (false == m_gauge.enabled || m_gauge.track == nullptr))
@@ -841,7 +842,7 @@ void editor_mode::render_gauge_hits()
ImGui::EndChild();
}
bool editor_mode::render_gauge_choice(char const *Label, int &Index, bool const Road)
bool gauge_tool::render_gauge_choice(char const *Label, int &Index, bool const Road)
{
bool changed{false};
ImGui::PushID(Label);
@@ -863,7 +864,7 @@ bool editor_mode::render_gauge_choice(char const *Label, int &Index, bool const
return changed;
}
bool editor_mode::render_gauge_outline(int const Index)
bool gauge_tool::render_gauge_outline(int const Index)
{
if (Index < 0)
return false;
@@ -884,3 +885,23 @@ bool editor_mode::render_gauge_outline(int const Index)
ImGui::TreePop();
return edited;
}
editor_selftest_result gauge_tool::selftest(std::string const &Command, std::istringstream &Words)
{
if (Command == "gauge")
{
std::string name;
Words >> name;
if (auto *track{simulation::Paths.find(name)})
{
scan_gauge(*track);
WriteLog(format("SELFTEST gauge %s: %d hits", name.c_str(), static_cast<int>(m_gauge.line.hits.size())));
for (auto const &hit : m_gauge.line.hits)
WriteLog(format("SELFTEST gauge hit %s depth %.3f at %.2f %.2f %.2f", hit.model.c_str(), hit.depth, hit.point.x, hit.point.y, hit.point.z));
}
else
WriteLog("SELFTEST gauge " + name + ": no such track");
return editor_selftest_result::handled;
}
return editor_selftest_result::unhandled;
}