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

feat(track): 3D sleepers and switch timbers, blade heel and throw from templates, one rail carving pass

- sleepers3d / sleepers3dplain / sleepers3dbed in eu07.ini: timbers put together from the begin, main and end parts of a model
  and stretched to their length, plain sleepers of their own model; tracks whose plain sleepers would touch are laid as one
  cluster, lines of timbers led by priority and turned to the bisectors of frogs and crossings at a limited rate, whole timbers
  under crossings, split ones between tracks with room to part them, gaps filled per rail and overlaps shortened or dropped;
  clusters worked out in a background thread while driving, on demand in the editor
- the ballast can be left out under the beams (sleepers3dbed no)
- blades get their heel and throw from the switch template or blades <heel> <throw> in the scenery; blades of double switches
  run on into the track linking them to the next switch
- rail cutting at frogs, wing rails, movable noses and switch crossings done by one carving pass (RailCarve)
- tint of the rail treads applied to the colour only, without the matte band at the frog
- a switch trailed through with a movable nose set the other way derails the vehicle
- self-tests: sleepercheck, sharedzones, beamsnear, throw, sleepersbg
This commit is contained in:
maj00r
2026-10-17 23:28:36 +02:00
parent 21eca4d9a6
commit d25f20a56c
49 changed files with 9802 additions and 848 deletions

View File

@@ -13,16 +13,25 @@ http://mozilla.org/MPL/2.0/.
#include "editor/editorFormat.hpp"
#include "editor/editorIncludeInfo.hpp"
#include "world/Segment.h"
#include "world/Track.h"
#include "world/TrackRails.h"
#include "scene/scenelayers.h"
#include "simulation/simulation.h"
#include "utilities/Globals.h"
#include "utilities/translation.h"
#include "utilities/utilities.h"
#include "imgui/imgui.h"
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <iterator>
#include <map>
#include <sstream>
namespace
{
@@ -307,3 +316,64 @@ bool editor_mode::render_switch_drive_choice()
}
return changed;
}
// a key by the movable nose of each switch with a drive, the frog is far from the drive at the start of the switch
bool editor_mode::nose_controls(std::vector<std::string> &Rootstatements)
{
if (scene::Layers.empty())
return false;
std::string root{scene::Layers.layer(scene::layer_handle{1}).name};
if (auto const slash{root.find_last_of("/\\")}; slash != std::string::npos)
root.erase(0, slash + 1);
if (auto const dot{root.rfind('.')}; dot != std::string::npos)
root.erase(dot);
if (root.empty())
return false;
auto const file{root + "_dzioby.scm"};
std::ostringstream text;
auto noses{0};
for (auto *track : simulation::Paths.sequence())
{
if (track == nullptr || track->m_editorremoved || track->eType != tt_Switch || track->SwitchExtension == nullptr || false == track->SwitchExtension->m_movablenose || track->name().empty())
continue;
auto const &segments{track->SwitchExtension->Segments};
auto const frog{track->frog()};
if (false == frog.valid || segments[0] == nullptr || frog.angle <= 0.0 || false == find_switch_drive(*track).has_value())
continue;
auto const &name{track->name()};
// where the inner rails cross, on the gauge line of the main path
glm::dvec3 point, across;
segments[0]->plan_frame(frog.at[0], point, across);
auto const nose{point + across * (frog.side[0] * 0.5 * std::abs(track->fTrackWidth))};
auto const range{5.0 + track_rails::movable_nose_length(std::tan(frog.angle))};
text << "node -1 0 " << name << "_dziob eventlauncher " << format("%.3f %.3f %.3f %.1f", nose.x, nose.y, nose.z, range) << " t 0 " << name << "+ " << name << "- end\r\n";
++noses;
}
auto const path{Global.asCurrentSceneryPath + file};
std::error_code error;
auto const exists{std::filesystem::exists(path, error)};
if (noses == 0 && false == exists)
return false;
auto const content{"// made by the scenery editor on each save: T and Shift+T by the movable nose throw its switch, as by its drive\r\n" + text.str()};
std::string current;
{
std::ifstream input{path, std::ios_base::binary};
current.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
}
if (current != content)
{
std::ofstream output{path, std::ios_base::binary | std::ios_base::trunc};
output << content;
}
auto included{m_nose_included};
for (std::size_t handle = 1; handle <= scene::Layers.size() && false == included; ++handle)
{
auto name{scene::Layers.layer(static_cast<scene::layer_handle>(handle)).name};
std::replace(name.begin(), name.end(), '\\', '/');
included = ToLower(name) == ToLower(file) || ToLower(name).ends_with("/" + ToLower(file));
}
if (included)
return false;
Rootstatements.push_back("include " + file + " end");
return true;
}