mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-02 12:49:13 +01:00
feat(editor): the signalling mode numbers the switches of a station along it and names them after its code, the drives and the switch records follow, and an undo of names passed round among the tracks leaves the drives right
This commit is contained in:
@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "world/Track.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <unordered_set>
|
||||
@@ -291,6 +292,12 @@ std::optional<layout> find(TTrack &From, options const &Options)
|
||||
result.km = best.origin / 1000.0;
|
||||
}
|
||||
}
|
||||
// without the km the station runs from the west to the east, as the map shows it
|
||||
if (false == result.kilometrage && map_of(result.axis.back()).x < map_of(result.axis.front()).x)
|
||||
{
|
||||
std::reverse(result.axis.begin(), result.axis.end());
|
||||
measure();
|
||||
}
|
||||
// the paths, laid out along the axis
|
||||
auto const add = [&](TTrack &Track, bool const Approach) {
|
||||
for (int index = 0; index < static_cast<int>(Track.m_paths.size()); ++index)
|
||||
@@ -391,6 +398,49 @@ std::vector<TTrack *> stations(options const &Options)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<unit> numbering(layout const &Layout, bool const Reversed)
|
||||
{
|
||||
std::unordered_set<TTrack const *> members;
|
||||
for (auto const &entry : Layout.paths)
|
||||
if (false == entry.approach)
|
||||
members.insert(entry.track);
|
||||
std::unordered_set<TTrack const *> taken;
|
||||
std::vector<unit> result;
|
||||
for (auto *track : Layout.switches)
|
||||
{
|
||||
if (track->eType == tt_Table || taken.count(track) > 0)
|
||||
continue;
|
||||
unit entry;
|
||||
if (auto const record{switch_store::named(*track)})
|
||||
{
|
||||
entry.record = record->name;
|
||||
if (record->kind != "switch")
|
||||
for (auto const &name : record->parts)
|
||||
if (auto *part{simulation::Paths.find(name)}; part != nullptr && members.count(part) > 0 && taken.insert(part).second)
|
||||
entry.parts.push_back(part);
|
||||
}
|
||||
if (taken.insert(track).second)
|
||||
entry.parts.push_back(track);
|
||||
entry.chainage = std::numeric_limits<double>::max();
|
||||
for (auto const *part : entry.parts)
|
||||
entry.chainage = std::min(entry.chainage, project(Layout, end_of(*part, 0, false)).x);
|
||||
result.push_back(std::move(entry));
|
||||
}
|
||||
std::stable_sort(result.begin(), result.end(), [&](unit const &A, unit const &B) { return Reversed ? A.chainage > B.chainage : A.chainage < B.chainage; });
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string switch_name(std::string const &Code, int const Number, std::size_t const Part, std::size_t const Parts)
|
||||
{
|
||||
std::string result;
|
||||
for (auto const c : Code)
|
||||
result += static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
result += '_' + std::to_string(Number);
|
||||
if (Parts > 1)
|
||||
result += static_cast<char>('a' + std::min<std::size_t>(Part, 25));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TTrack *> switches_of(TTrack &Switch, options const &Options)
|
||||
{
|
||||
return collect(Switch, Options).switches;
|
||||
|
||||
@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
@@ -51,6 +52,14 @@ struct layout
|
||||
double km{0.0}; // at chainage 0, when it does
|
||||
};
|
||||
|
||||
// what shares a number of the station: a switch, or the switches of a slip, the two of a double switch, the paths of a crossing
|
||||
struct unit
|
||||
{
|
||||
std::vector<TTrack *> parts;
|
||||
std::string record; // the name of its record of the switches, empty without one
|
||||
double chainage{0.0}; // of the start of its first part along the station
|
||||
};
|
||||
|
||||
// the station of the switch, or of the plain track near one
|
||||
std::optional<layout> find(TTrack &From, options const &Options = {});
|
||||
// the chainage along the axis and the offset to the left of it, as the map shows it
|
||||
@@ -59,6 +68,10 @@ glm::dvec2 project(layout const &Layout, glm::dvec3 const &Point);
|
||||
double km_of(layout const &Layout, double const Chainage);
|
||||
// one switch of each station of the scenery
|
||||
std::vector<TTrack *> stations(options const &Options = {});
|
||||
// the switches of the station by their numbers: along the chainage, or against it when Reversed; turntables have none
|
||||
std::vector<unit> numbering(layout const &Layout, bool const Reversed);
|
||||
// <code>_<number>, each part of a unit of several with a letter of its own: bpd_15a
|
||||
std::string switch_name(std::string const &Code, int const Number, std::size_t const Part, std::size_t const Parts);
|
||||
// the switches of the station of the switch, without laying it out
|
||||
std::vector<TTrack *> switches_of(TTrack &Switch, options const &Options = {});
|
||||
|
||||
|
||||
@@ -330,6 +330,42 @@ void forget(std::string const &Name)
|
||||
mark(layer);
|
||||
}
|
||||
|
||||
void rename(std::map<std::string, std::string> const &Parts, std::map<std::string, std::string> const &Bases)
|
||||
{
|
||||
load();
|
||||
auto const renamed = [](std::map<std::string, std::string> const &Names, std::string &Name) {
|
||||
auto const found{Names.find(Name)};
|
||||
if (found == Names.end() || found->second == Name)
|
||||
return false;
|
||||
Name = found->second;
|
||||
return true;
|
||||
};
|
||||
std::set<scene::layer_handle> layers;
|
||||
for (auto &entry : g_records)
|
||||
{
|
||||
auto changed{renamed(entry.kind == "slip" || entry.kind == "crossing" ? Bases : Parts, entry.name)};
|
||||
for (auto &part : entry.parts)
|
||||
changed = renamed(Parts, part) || changed;
|
||||
if (changed)
|
||||
layers.insert(entry.layer);
|
||||
}
|
||||
for (auto const layer : layers)
|
||||
mark(layer);
|
||||
g_changed = g_changed || false == layers.empty();
|
||||
}
|
||||
|
||||
void number(std::string const &Name, std::string const &Number)
|
||||
{
|
||||
load();
|
||||
for (auto &entry : g_records)
|
||||
if (entry.kind != "connection" && entry.name == Name && entry.number != Number)
|
||||
{
|
||||
entry.number = Number;
|
||||
mark(entry.layer);
|
||||
g_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void tidy()
|
||||
{
|
||||
load();
|
||||
|
||||
@@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -72,6 +73,11 @@ void put(record Entry, scene::layer_handle const Layer);
|
||||
void place(record &Entry, TTrack const &First);
|
||||
void classify(record &Entry, TTrack const &Switch);
|
||||
void forget(std::string const &Name);
|
||||
// the records follow renamed switches: their parts and the records named after them; Bases renames the records of slips and
|
||||
// crossings, whose names aren't the names of their parts
|
||||
void rename(std::map<std::string, std::string> const &Parts, std::map<std::string, std::string> const &Bases);
|
||||
// the number of the switch, slip or crossing of the record of the name, as the lists of the switches give it
|
||||
void number(std::string const &Name, std::string const &Number);
|
||||
// on save: the records follow the renamed switches, the ones whose paths are gone are dropped
|
||||
void tidy();
|
||||
// "Rz 60E1-500-1:12 L", as the type is written on the lists of the switches
|
||||
|
||||
@@ -367,7 +367,7 @@ editor_track::name_uses editor_track::uses_of_name(TTrack const &Track)
|
||||
return result;
|
||||
}
|
||||
|
||||
void editor_track::rename(TTrack &Track, std::string const &Name)
|
||||
void editor_track::rename(TTrack &Track, std::string const &Name, std::vector<scene::instance_handle> const &Kept)
|
||||
{
|
||||
auto const old{Track.name()};
|
||||
if (old == Name)
|
||||
@@ -388,7 +388,7 @@ void editor_track::rename(TTrack &Track, std::string const &Name)
|
||||
std::string file;
|
||||
std::vector<std::string> values;
|
||||
auto const index{track_parameter(handle, file, values)};
|
||||
if (index < 0 || lower_name(values[index]) != old)
|
||||
if (index < 0 || lower_name(values[index]) != old || std::find(Kept.begin(), Kept.end(), handle) != Kept.end())
|
||||
continue;
|
||||
values[index] = Name;
|
||||
scene::Layers.modify(handle, editor_includes::compose_directive(file, values));
|
||||
|
||||
@@ -86,7 +86,8 @@ class editor_track
|
||||
std::vector<std::string> loose;
|
||||
};
|
||||
static name_uses uses_of_name(TTrack const &Track);
|
||||
static void rename(TTrack &Track, std::string const &Name);
|
||||
// the includes of Kept keep their directives: an undo step puts them back on its own
|
||||
static void rename(TTrack &Track, std::string const &Name, std::vector<scene::instance_handle> const &Kept = {});
|
||||
|
||||
// lists of the events of the path, in the order of event_keyword(): event0, event1, event2, eventall0, eventall1, eventall2
|
||||
static std::vector<std::pair<std::string, basic_event *>> &events(TTrack &Track, int const Index);
|
||||
|
||||
Reference in New Issue
Block a user