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

Catenary editor: save the catenary by the active layer

This commit is contained in:
2026-10-26 18:56:28 +01:00
parent 2321180051
commit 5f93c7c20d
8 changed files with 137 additions and 9 deletions

View File

@@ -2988,13 +2988,32 @@ bool editor_mode::save()
rootstatements.emplace_back("heightmap_terrain " + m_streamer.name() + " endheightmap_terrain");
}
auto const terrainadded{false == rootstatements.empty()};
if (m_profile.changed)
profile_store();
switch_store::tidy();
switch_store::settle();
infra_store();
// the catenary (cantilevers on the poles) lives in files of its own; a file made in the editor needs the directive
// the catenary (cantilevers on the poles) lives in files of its own; a file made in the editor needs the directive, in the file
// of the layer it was made on (the scenario file when that layer can't take it)
std::vector<std::string> catenarynew;
std::map<scene::layer_handle, std::vector<std::string>> layerstatements;
auto const same_file = [](std::string const &A, std::string const &B) {
auto a{std::filesystem::path(A).lexically_normal().generic_string()}, b{std::filesystem::path(B).lexically_normal().generic_string()};
std::transform(a.begin(), a.end(), a.begin(), [](unsigned char const C) { return static_cast<char>(std::tolower(C)); });
std::transform(b.begin(), b.end(), b.begin(), [](unsigned char const C) { return static_cast<char>(std::tolower(C)); });
return a == b;
};
for (auto const &file : catenary_scene_files())
{
// a catenary file of the name of a scenery file would take its place, and the scenery its directive
for (std::size_t layer = 1; layer <= scene::Layers.size(); ++layer)
if (scene::Layers.listed(static_cast<scene::layer_handle>(layer)) && same_file(scene::Layers.layer(static_cast<scene::layer_handle>(layer)).name, file))
{
ui()->set_status(format(STR_C("The catenary couldn't be saved: its file \"%s\" is a file of the scenery; give the catenary another file"), file.c_str()), true);
return false;
}
}
if (catenary_scene_changed())
{
std::string message;
@@ -3007,7 +3026,11 @@ bool editor_mode::save()
}
for (auto const &file : catenary_scene_new_files())
{
rootstatements.emplace_back("catenary " + file + " endcatenary");
auto const layer{static_cast<scene::layer_handle>(catenary_scene_file_layer(file))};
if (layer > 1 && scene::Layers.accepts(layer))
layerstatements[scene::Layers.resolve(layer)].emplace_back("catenary " + file + " endcatenary");
else
rootstatements.emplace_back("catenary " + file + " endcatenary");
catenarynew.push_back(file);
}
if (false == m_saved_camera.has_value() || glm::distance(m_saved_camera->first, glm::dvec3{Camera.Pos}) > 0.5 || glm::distance(m_saved_camera->second, glm::vec3{Camera.Angle}) > 0.01f)
@@ -3020,7 +3043,6 @@ bool editor_mode::save()
m_orthophoto_mark = map;
scene::Layers.mark(scene::layer_handle{1}, "//$o", {map});
}
auto const terrainadded{false == rootstatements.empty()};
auto const controls{turntable_controls(rootstatements)};
auto const noses{nose_controls(rootstatements)};
std::vector<std::string> trailing;
@@ -3033,7 +3055,7 @@ bool editor_mode::save()
trailing.insert(trailing.end(), trainset.lines.begin(), trainset.lines.end());
if (placed == 0)
starter_trainset(trailing);
auto const result = scene::Layers.save(rootstatements, trailing);
auto const result = scene::Layers.save(rootstatements, trailing, layerstatements);
if (result.success && controls)
m_turntable_included = true;
if (result.success && noses)

View File

@@ -24,6 +24,7 @@ http://mozilla.org/MPL/2.0/.
#include "world/Track.h"
#include "world/catenary_scene.h"
#include "world/catenary_layout.h"
#include "scene/scenelayers.h"
#include "imgui/imgui.h"
#include "utilities/translation.h"
@@ -688,6 +689,35 @@ double catenary_editor::span_recommended(double const Radius) const
return wanted > 0.0 ? std::floor(wanted * 2.0) / 2.0 : 0.0;
}
void catenary_editor::catenary_file_follow()
{
auto &tool{m_catenary};
auto const active{scene::Layers.active()};
if (false == scene::Layers.valid(active))
return; // the scenery wasn't opened for editing: no layers
// the catenary file of the active layer (the one it includes), or a new one named after it next to it; not while a chain
// goes on (a chain is in one file) nor when the user gave the file
if (false == tool.file_own && tool.last < 0 && tool.selected < 0)
{
std::string wanted;
for (auto const &file : catenary_scene_files())
if (catenary_scene_file_layer(file) == active)
{
wanted = file;
break;
}
if (wanted.empty())
{
std::filesystem::path const name{scene::Layers.layer(active).name};
wanted = (name.parent_path() / (name.stem().string() + "_siec.scm")).generic_string();
}
std::snprintf(tool.file, sizeof(tool.file), "%s", wanted.c_str());
}
// a file the scenery doesn't include yet gets its directive in the file of the active layer
if (tool.file[0] != '\0')
catenary_scene_file_layer(tool.file, active);
}
bool catenary_editor::typed_span() const
{
auto const &tool{m_catenary};
@@ -4230,9 +4260,29 @@ void catenary_editor::render_catenary_cantilever_ui()
ImGui::PushItemWidth(180.0f);
if (tool.selected < 0)
{
ImGui::InputText(STR_C("Catenary file"), tool.file, sizeof(tool.file));
if (ImGui::InputText(STR_C("Catenary file"), tool.file, sizeof(tool.file)))
tool.file_own = true;
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("File in the scenery directory the new poles go to; a new one is added to the scenery with the directive catenary <file> endcatenary when it's saved"));
ImGui::SetTooltip("%s", STR_C("File in the scenery directory the new poles go to; a new one is added to the scenery with the directive catenary <file> endcatenary when it's saved, in the file of the active layer. By default the catenary file of the active layer, or a new one named after it"));
if (tool.file_own)
{
ImGui::SameLine();
if (ImGui::SmallButton(STR_C("by the layer")))
tool.file_own = false;
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("The catenary file follows the active layer again"));
}
{
// where it ends up: the file, and the layer whose file includes it
auto const layer{static_cast<scene::layer_handle>(catenary_scene_file_layer(tool.file))};
auto const files{catenary_scene_files()};
auto const known{std::find(files.begin(), files.end(), std::string{tool.file}) != files.end()};
auto const fresh{catenary_scene_new_files()};
auto const created{known && std::find(fresh.begin(), fresh.end(), std::string{tool.file}) != fresh.end()};
auto const layername{scene::Layers.valid(layer) ? scene::Layers.layer(layer).name : std::string{}};
if (false == layername.empty())
ImGui::TextDisabled("%s", format(known && false == created ? STR_C("included by %s") : STR_C("new: the save writes it and its directive into %s"), layername.c_str()).c_str());
}
render_catenary_chain_state();
}
else
@@ -4643,6 +4693,7 @@ void catenary_editor::render_catenary_ui()
{
auto &tool{m_catenary};
catenary_scan();
catenary_file_follow();
if (tool.selected < 0 && tool.bend_user.has_value())
{
tool.bend = *tool.bend_user;

View File

@@ -164,9 +164,12 @@ struct catenary_editor
float span_length{60.0f};
bool show_staggers{true}; // the staggers written at the poles of the selected chain
std::optional<int> bend_user; // "cards for" as the user had it before a pole was selected (the pole's own while it is)
bool file_own{false}; // the catenary file was given by the user: it doesn't follow the active layer
};
catenary_tool m_catenary;
void catenary_scan();
// the catenary file of the new poles follows the active layer of the scenery
void catenary_file_follow();
// Placing: the spot of a new pole, which takes the zigzag proposed after the last pole and the step of the span
bool catenary_spot_at(TTrack &Track, int const Path, glm::dvec3 const &Point, glm::dvec3 const &Cursor, int const Side, catenary_spot &Spot, bool const Placing = false) const;
// the zigzag (Iet-107): the largest staggers allowed for the speed of the line, and those the next poles get