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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user