17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-29 22:07:28 +01:00

fix(editor): the drive of a switch follows the switch: moved, turned, its grade or cant changed with the gizmo or any other change of the switch, the include gets the new position, direction and rot.x/rot.z of the start of the switch, in the same undo step; self-test drives prints the parameters of the drive

This commit is contained in:
maj00r
2026-10-11 19:23:59 +02:00
parent 4b785f3789
commit b103a561e0
4 changed files with 109 additions and 20 deletions

View File

@@ -1407,6 +1407,9 @@ class editor_mode : public application_mode, private editor_track::observer
std::vector<standing_template> standing_templates(std::function<bool(std::string const &)> const &Accept) const;
bool find_switch_drive(TTrack const &Switch, standing_template &Drive, int &Family, int &Index);
bool replace_switch_drive(TTrack &Switch, int Family, bool Flip);
bool switch_drive_spot(TTrack const &Switch, glm::dvec3 &Location, double &Yaw, glm::dvec2 &Tilt, bool &Rightswitch) const;
void switch_drive_captured(TTrack const &Track);
void switch_drives_committed(std::vector<TTrack *> const &Tracks);
// places them in the active layer, as one step of the undo. returns: how many were placed
std::size_t place_templates(std::vector<template_item> const &Items, std::string &Error);
// moves them, as one step of the undo
@@ -1940,6 +1943,7 @@ class editor_mode : public application_mode, private editor_track::observer
std::vector<std::pair<scene::layer_handle, std::string>> m_bindings_unresolved; // lines kept as they are
bool m_bindings_loaded{false};
std::vector<infra::object_state> m_infra_buffer; // states of the objects before the change in progress
std::vector<std::pair<scene::instance_handle, std::string>> m_drive_buffer;
bool m_infra_suspended{false};
void infra_load();
void infra_store();

View File

@@ -1128,6 +1128,7 @@ void editor_mode::infra_buffer(infra::binding const &Binding, bool const Refresh
void editor_mode::track_captured(TTrack const &Track)
{
sweeps_captured(Track);
switch_drive_captured(Track);
if (m_infra_suspended || false == m_infra.follow)
return;
infra_load();
@@ -1166,6 +1167,7 @@ void editor_mode::track_captured(TTrack const &Track)
void editor_mode::tracks_committed(std::vector<TTrack *> const &Tracks)
{
sweeps_committed(Tracks);
switch_drives_committed(Tracks);
if (m_infra_suspended || false == m_infra.follow)
return;
infra_load();

View File

@@ -413,7 +413,11 @@ void editor_mode::selftest_step()
std::string files;
for (auto const &standing : standing_templates([](std::string const &File) { return File.find("napedy/") != std::string::npos; }))
if (false == standing.values.empty() && standing.values[0] == name)
{
files += " " + standing.file;
for (std::size_t i = 1; i < standing.values.size(); ++i)
files += (i == 1 ? " (" : " ") + standing.values[i] + (i + 1 == standing.values.size() ? ")" : "");
}
for (scene::instance_handle handle = 1; handle <= scene::Layers.instance_count(); ++handle)
if (scene::Layers.tracked(handle) && scene::Layers.instance(handle).file != nullptr && scene::Layers.instance(handle).file->find("napedy") != std::string::npos)
files += format(" [%d %s removed %d dead %d]", static_cast<int>(handle), scene::Layers.instance(handle).file->c_str(), scene::Layers.instance(handle).removed ? 1 : 0, scene::Layers.instance(handle).dead ? 1 : 0);

View File

@@ -1239,6 +1239,8 @@ void editor_mode::push_track_snapshot(std::vector<std::pair<TTrack *, editor_tra
infra_attach(snap);
snap.alignments = alignment_store::take_changes();
snap.switch_records = switch_store::take_changes();
snap.directives.insert(snap.directives.end(), m_drive_buffer.begin(), m_drive_buffer.end());
m_drive_buffer.clear();
m_history.push_back(std::move(snap));
g_redo.clear();
}
@@ -1478,6 +1480,7 @@ void editor_mode::restore_track_snapshot(EditorSnapshot const &Snapshot, std::ve
for (auto const &entry : Snapshot.infra)
infra_restore_state(entry);
m_infra_buffer.clear();
m_drive_buffer.clear();
m_infra_suspended = false;
if (false == m_route.chain.tracks.empty())
{
@@ -6649,22 +6652,106 @@ std::string editor_mode::switch_name_for_new() const
}
}
bool editor_mode::switch_drive_spot(TTrack const &Switch, glm::dvec3 &Location, double &Yaw, glm::dvec2 &Tilt, bool &Rightswitch) const
{
if (Switch.eType != tt_Switch || Switch.m_paths.size() < 2)
return false;
auto const &main{Switch.m_paths[0]};
auto const &diverging{Switch.m_paths[1]};
auto const start{main.points[segment_data::point::start]};
auto const &control{main.points[segment_data::point::control1]};
auto const along{control != glm::dvec3{} ? control : main.points[segment_data::point::end] - start};
auto heading{plan_of(along)};
if (glm::length(heading) < 1e-9)
return false;
heading = glm::normalize(heading);
glm::dvec2 const right{-heading.y, heading.x};
Rightswitch = glm::dot(plan_of(diverging.points[segment_data::point::end] - start), right) > 0.0;
Location = start;
auto const yaw{glm::degrees(std::atan2(heading.x, heading.y))};
Yaw = yaw < 0.0 ? yaw + 360.0 : yaw;
auto const run{glm::length(plan_of(along))};
auto const roll{static_cast<double>(main.rolls[0])};
Tilt = {-glm::degrees(std::atan(along.y / run)), roll};
if (Global.bRollFix)
Location.y += 0.75 * std::abs(std::sin(glm::radians(roll)));
return true;
}
void editor_mode::switch_drive_captured(TTrack const &Track)
{
if (Track.eType != tt_Switch || m_infra_suspended)
return;
standing_template drive;
int family{-1};
int variant{0};
if (false == find_switch_drive(Track, drive, family, variant))
return;
if (std::any_of(m_drive_buffer.begin(), m_drive_buffer.end(), [&](auto const &Entry) { return Entry.first == drive.instance; }))
return;
m_drive_buffer.emplace_back(drive.instance, scene::Layers.directive(drive.instance));
}
void editor_mode::switch_drives_committed(std::vector<TTrack *> const &Tracks)
{
if (m_infra_suspended)
return;
for (auto *track : Tracks)
{
if (track == nullptr || track->m_editorremoved || track->eType != tt_Switch)
continue;
standing_template drive;
int family{-1};
int variant{0};
glm::dvec3 location;
double yaw;
glm::dvec2 tilt;
bool rightswitch;
if (false == find_switch_drive(*track, drive, family, variant) || false == switch_drive_spot(*track, location, yaw, tilt, rightswitch))
continue;
auto const &included{scene::Layers.instance(drive.instance)};
include_info info;
std::string error;
if (included.file == nullptr || false == editor_includes::load(*included.file, info, error))
continue;
auto const local{location - included.context.offset};
auto values{drive.values};
for (auto const &parameter : info.parameters)
{
if (parameter.id < 1 || parameter.id > static_cast<int>(values.size()))
continue;
auto &value{values[parameter.id - 1]};
if (parameter.role == "pos.x")
value = editor_includes::number(local.x);
else if (parameter.role == "pos.y")
value = editor_includes::number(local.y);
else if (parameter.role == "pos.z")
value = editor_includes::number(local.z);
else if (parameter.role == "rot.y")
value = editor_includes::number(yaw);
else if (parameter.role == "rot.x")
value = editor_includes::number(tilt.x);
else if (parameter.role == "rot.z")
value = editor_includes::number(tilt.y);
}
auto const directive{editor_includes::compose_directive(*included.file, values)};
if (directive != scene::Layers.directive(drive.instance))
set_include_directive(drive.instance, directive);
}
}
bool editor_mode::place_switch_drive(TTrack &Switch)
{
auto &tool{m_switch};
scan_switch_drives();
if (tool.drive < 0 || tool.drive >= static_cast<int>(tool.drives.size()) || Switch.eType != tt_Switch || Switch.m_paths.size() < 2)
return false;
auto const &main{Switch.m_paths[0]};
auto const &diverging{Switch.m_paths[1]};
auto const start{main.points[segment_data::point::start]};
auto const &control{main.points[segment_data::point::control1]};
auto heading{plan_of(control != glm::dvec3{} ? control : main.points[segment_data::point::end] - start)};
if (glm::length(heading) < 1e-9)
glm::dvec3 location;
double yaw;
glm::dvec2 tilt;
bool rightswitch;
if (false == switch_drive_spot(Switch, location, yaw, tilt, rightswitch))
return false;
heading = glm::normalize(heading);
glm::dvec2 const right{-heading.y, heading.x};
bool const rightswitch{glm::dot(plan_of(diverging.points[segment_data::point::end] - start), right) > 0.0};
bool const driveright{(tool.drive_side == 0) == rightswitch};
auto const &family{tool.drives[tool.drive]};
template_item item;
@@ -6674,19 +6761,11 @@ bool editor_mode::place_switch_drive(TTrack &Switch)
tool.status = format(STR_C("The drive %s has no variant for a %s switch with the drive on the %s"), family.name.c_str(), rightswitch ? STR_C("right") : STR_C("left"), driveright ? STR_C("right") : STR_C("left"));
return false;
}
item.location = start;
auto yaw{glm::degrees(std::atan2(heading.x, heading.y))};
item.yaw = yaw < 0.0 ? yaw + 360.0 : yaw;
item.location = location;
item.yaw = yaw;
item.described = true;
item.track = Switch.name();
{
auto const along{control != glm::dvec3{} ? control : main.points[segment_data::point::end] - start};
auto const run{glm::length(plan_of(along))};
auto const roll{static_cast<double>(main.rolls[0])};
item.tilt = {run > 1e-9 ? -glm::degrees(std::atan(along.y / run)) : 0.0, roll};
if (Global.bRollFix)
item.location.y += 0.75 * std::abs(std::sin(glm::radians(roll)));
}
item.tilt = tilt;
standing_template standing;
int present{-1};
int variant{0};