mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-03 09:40:22 +01:00
feat(editor): the kept alignments and switches after a drag of the gizmo or of a point: a line all of whose paths are moved or turned as a whole takes its kept design along; paths pulled out of a kept design, or given another cant, are told about on the status line with the way back; a switch moved or turned as a whole keeps its type and its record follows it, with its km; a switch bent out of the shape of its type loses it and is told about (//$r records keep the shape of the switch); all of it in the same undo step as the drag; Polish translation
This commit is contained in:
@@ -36,6 +36,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -636,6 +637,17 @@ class editor_mode : public application_mode, private editor_track::observer
|
|||||||
void restore_track_snapshot(EditorSnapshot const &Snapshot, std::vector<EditorSnapshot> &Opposite, bool const Undo);
|
void restore_track_snapshot(EditorSnapshot const &Snapshot, std::vector<EditorSnapshot> &Opposite, bool const Undo);
|
||||||
// changes of the kept alignments and switches go into the last step of the history, made just before them
|
// changes of the kept alignments and switches go into the last step of the history, made just before them
|
||||||
void records_to_history();
|
void records_to_history();
|
||||||
|
// the paths a drag of the gizmo takes, to tell after it what became of the kept alignments and switches
|
||||||
|
struct record_watch
|
||||||
|
{
|
||||||
|
bool active{false};
|
||||||
|
std::vector<TTrack *> moving;
|
||||||
|
std::vector<std::pair<glm::dvec3, glm::dvec3>> before; // ends of the first path of each moving track
|
||||||
|
std::map<int, std::vector<TTrack *>> on; // the kept alignments and the moving paths on them
|
||||||
|
std::set<int> whole; // the kept alignments all of whose paths move
|
||||||
|
} m_record_watch;
|
||||||
|
void records_watch_begin();
|
||||||
|
void records_watch_end();
|
||||||
editor_track::point_ref m_track_point;
|
editor_track::point_ref m_track_point;
|
||||||
std::vector<TTrack *> m_track_drag;
|
std::vector<TTrack *> m_track_drag;
|
||||||
std::vector<std::pair<TTrack *, editor_track::point_ref>> m_track_drag_points;
|
std::vector<std::pair<TTrack *, editor_track::point_ref>> m_track_drag_points;
|
||||||
|
|||||||
@@ -917,6 +917,7 @@ void editor_mode::track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_o
|
|||||||
for (auto *dragged : m_track_drag)
|
for (auto *dragged : m_track_drag)
|
||||||
states.emplace_back(dragged, editor_track::capture(*dragged));
|
states.emplace_back(dragged, editor_track::capture(*dragged));
|
||||||
push_track_snapshot(std::move(states));
|
push_track_snapshot(std::move(states));
|
||||||
|
records_watch_begin();
|
||||||
track_gizmo_hold();
|
track_gizmo_hold();
|
||||||
for (auto &link : drag.switches)
|
for (auto &link : drag.switches)
|
||||||
for (auto &member : link.cluster)
|
for (auto &member : link.cluster)
|
||||||
@@ -1097,6 +1098,7 @@ void editor_mode::track_gizmo_end(TTrack &Track)
|
|||||||
created.insert(created.end(), m_track_gizmo_drag.extra.begin(), m_track_gizmo_drag.extra.end());
|
created.insert(created.end(), m_track_gizmo_drag.extra.begin(), m_track_gizmo_drag.extra.end());
|
||||||
m_track_gizmo_drag.extra.clear();
|
m_track_gizmo_drag.extra.clear();
|
||||||
}
|
}
|
||||||
|
records_watch_end();
|
||||||
m_track_gizmo_using = false;
|
m_track_gizmo_using = false;
|
||||||
m_track_drag.clear();
|
m_track_drag.clear();
|
||||||
m_track_drag_points.clear();
|
m_track_drag_points.clear();
|
||||||
@@ -1239,6 +1241,146 @@ void editor_mode::push_track_snapshot(std::vector<std::pair<TTrack *, editor_tra
|
|||||||
g_redo.clear();
|
g_redo.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void editor_mode::records_watch_begin()
|
||||||
|
{
|
||||||
|
auto &watch{m_record_watch};
|
||||||
|
watch = {};
|
||||||
|
watch.active = true;
|
||||||
|
watch.moving = m_track_drag;
|
||||||
|
for (auto const &link : m_track_gizmo_drag.switches)
|
||||||
|
for (auto const &member : link.cluster)
|
||||||
|
if (std::find(watch.moving.begin(), watch.moving.end(), member.first) == watch.moving.end())
|
||||||
|
watch.moving.push_back(member.first);
|
||||||
|
auto const lies_on = [](int const Record, TTrack const &Track) {
|
||||||
|
bezier const curve{Track.m_paths.front()};
|
||||||
|
for (auto const t : {0.0, 0.5, 1.0})
|
||||||
|
if (false == alignment_store::on_record(Record, curve.point(t), alignment_store::tolerance).has_value())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
for (auto *track : watch.moving)
|
||||||
|
{
|
||||||
|
auto const &path{track->m_paths.front()};
|
||||||
|
watch.before.emplace_back(path.points[segment_data::point::start], path.points[segment_data::point::end]);
|
||||||
|
if (track->eType != tt_Normal)
|
||||||
|
continue;
|
||||||
|
if (auto const found{alignment_store::on_track(*track)})
|
||||||
|
watch.on[found->record].push_back(track);
|
||||||
|
}
|
||||||
|
for (auto const &entry : watch.on)
|
||||||
|
{
|
||||||
|
bool whole{true};
|
||||||
|
for (auto *track : simulation::Paths.sequence())
|
||||||
|
if (track != nullptr && false == track->m_editorremoved && track->eType == tt_Normal && false == track->m_paths.empty() &&
|
||||||
|
std::find(watch.moving.begin(), watch.moving.end(), track) == watch.moving.end() && lies_on(entry.first, *track))
|
||||||
|
{
|
||||||
|
whole = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (whole)
|
||||||
|
watch.whole.insert(entry.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// what the drag of the gizmo did to the kept alignments and switches: an alignment all of whose paths were moved or turned as a
|
||||||
|
// whole goes along with them, paths pulled out of an alignment or given another cant are told about, as are switches bent out
|
||||||
|
// of the shape of their type; switches moved as a whole take their records along
|
||||||
|
void editor_mode::records_watch_end()
|
||||||
|
{
|
||||||
|
auto &watch{m_record_watch};
|
||||||
|
if (false == watch.active)
|
||||||
|
return;
|
||||||
|
watch.active = false;
|
||||||
|
auto const index = [&](TTrack const *Track) { return static_cast<std::size_t>(std::find(watch.moving.begin(), watch.moving.end(), Track) - watch.moving.begin()); };
|
||||||
|
auto const chord = [](glm::dvec3 const &Start, glm::dvec3 const &End) {
|
||||||
|
auto const direction{plan_of(End - Start)};
|
||||||
|
return glm::length(direction) > 1e-9 ? glm::normalize(direction) : glm::dvec2{0.0, 1.0};
|
||||||
|
};
|
||||||
|
std::vector<std::string> notes;
|
||||||
|
int followed{0};
|
||||||
|
double departure{0.0}, cant{0.0};
|
||||||
|
int departed{0};
|
||||||
|
std::string layer;
|
||||||
|
for (auto const &[record, tracks] : watch.on)
|
||||||
|
{
|
||||||
|
if (watch.whole.count(record) > 0)
|
||||||
|
{
|
||||||
|
auto const &first{watch.before[index(tracks.front())]};
|
||||||
|
auto const &path{tracks.front()->m_paths.front()};
|
||||||
|
auto const from{chord(first.first, first.second)};
|
||||||
|
auto const to{chord(path.points[segment_data::point::start], path.points[segment_data::point::end])};
|
||||||
|
auto const angle{signed_angle(from, to)};
|
||||||
|
bool rigid{true};
|
||||||
|
for (auto *track : tracks)
|
||||||
|
{
|
||||||
|
auto const &was{watch.before[index(track)]};
|
||||||
|
auto const &now{track->m_paths.front()};
|
||||||
|
for (auto const &[old, current] : {std::pair{was.first, now.points[segment_data::point::start]}, std::pair{was.second, now.points[segment_data::point::end]}})
|
||||||
|
rigid = rigid && glm::distance(plan_of(path.points[segment_data::point::start]) + turned(plan_of(old) - plan_of(first.first), angle), plan_of(current)) <= 0.01;
|
||||||
|
}
|
||||||
|
if (rigid)
|
||||||
|
{
|
||||||
|
bool const moved{glm::distance(first.first, path.points[segment_data::point::start]) > 1e-4 || std::abs(angle) > 1e-7};
|
||||||
|
if (moved)
|
||||||
|
{
|
||||||
|
alignment_store::transform(record, first.first, from, path.points[segment_data::point::start], to);
|
||||||
|
++followed;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto const &records{alignment_store::records()};
|
||||||
|
auto const gauge{records[record].design.norms.gauge};
|
||||||
|
for (auto *track : tracks)
|
||||||
|
{
|
||||||
|
if (track->m_editorremoved)
|
||||||
|
continue;
|
||||||
|
auto const &path{track->m_paths.front()};
|
||||||
|
bezier const curve{path};
|
||||||
|
double largest{0.0};
|
||||||
|
for (auto const t : {0.0, 0.5, 1.0})
|
||||||
|
{
|
||||||
|
auto const found{alignment_store::on_record(record, curve.point(t), 1000.0)};
|
||||||
|
largest = std::max(largest, found.has_value() ? found->offset : 1000.0);
|
||||||
|
}
|
||||||
|
if (largest > alignment_store::tolerance)
|
||||||
|
{
|
||||||
|
++departed;
|
||||||
|
departure = std::max(departure, largest);
|
||||||
|
layer = scene::Layers.layer(records[record].layer).name;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto const end : {0, 1})
|
||||||
|
if (auto const found{alignment_store::on_record(record, curve.point(end), alignment_store::tolerance)})
|
||||||
|
{
|
||||||
|
auto const actual{gauge * std::sin(std::abs(glm::radians(static_cast<double>(path.rolls[end]))))};
|
||||||
|
cant = std::max(cant, std::abs(actual - alignment_store::cant_at(record, found->chainage)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (followed > 0)
|
||||||
|
notes.push_back(STR("The kept design of the line went along with its paths"));
|
||||||
|
if (departed > 0)
|
||||||
|
notes.push_back(format(STR_C("%d path(s) left the design kept in %s, by up to %.2f m: Ctrl+Z takes it back, the route design lays them by the design again or forgets it"), departed, layer.c_str(), departure));
|
||||||
|
if (cant > 5.0)
|
||||||
|
notes.push_back(format(STR_C("The cant differs from the kept design by up to %.0f mm"), cant));
|
||||||
|
switch_store::follow();
|
||||||
|
for (auto *track : watch.moving)
|
||||||
|
if (track->eType == tt_Switch && false == track->m_editorremoved)
|
||||||
|
if (auto const known{switch_store::named(*track)}; known.has_value() && false == switch_store::of(*track).has_value())
|
||||||
|
notes.push_back(format(STR_C("Switch %s lost the shape of its type %s: Ctrl+Z takes it back"), track->name().c_str(), switch_store::label(*known).c_str()));
|
||||||
|
records_to_history();
|
||||||
|
if (false == notes.empty())
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
for (auto const ¬e : notes)
|
||||||
|
text += (text.empty() ? "" : "\n") + note;
|
||||||
|
ui()->set_status(text, departed > 0 || cant > 5.0 || notes.size() > static_cast<std::size_t>(followed > 0 ? 1 : 0));
|
||||||
|
WriteLog("Editor: " + text, logtype::generic);
|
||||||
|
}
|
||||||
|
watch = {};
|
||||||
|
}
|
||||||
|
|
||||||
void editor_mode::records_to_history()
|
void editor_mode::records_to_history()
|
||||||
{
|
{
|
||||||
auto alignments{alignment_store::take_changes()};
|
auto alignments{alignment_store::take_changes()};
|
||||||
@@ -5291,6 +5433,7 @@ void editor_mode::point_drag_update()
|
|||||||
for (auto *dragged : m_track_drag)
|
for (auto *dragged : m_track_drag)
|
||||||
states.emplace_back(dragged, editor_track::capture(*dragged));
|
states.emplace_back(dragged, editor_track::capture(*dragged));
|
||||||
push_track_snapshot(std::move(states));
|
push_track_snapshot(std::move(states));
|
||||||
|
records_watch_begin();
|
||||||
}
|
}
|
||||||
screen_projection const projection;
|
screen_projection const projection;
|
||||||
glm::dvec3 position;
|
glm::dvec3 position;
|
||||||
@@ -5324,6 +5467,7 @@ void editor_mode::point_drag_finish()
|
|||||||
}
|
}
|
||||||
m_track_snap = {};
|
m_track_snap = {};
|
||||||
commit_track_drag(true);
|
commit_track_drag(true);
|
||||||
|
records_watch_end();
|
||||||
m_track_drag.clear();
|
m_track_drag.clear();
|
||||||
m_track_drag_points.clear();
|
m_track_drag_points.clear();
|
||||||
m_track_joints.clear();
|
m_track_joints.clear();
|
||||||
|
|||||||
@@ -1307,6 +1307,7 @@ bool editor_mode::track_set_begin(bool const Rotate)
|
|||||||
for (auto *track : m_track_drag)
|
for (auto *track : m_track_drag)
|
||||||
states.emplace_back(track, editor_track::capture(*track));
|
states.emplace_back(track, editor_track::capture(*track));
|
||||||
push_track_snapshot(std::move(states));
|
push_track_snapshot(std::move(states));
|
||||||
|
records_watch_begin();
|
||||||
track_gizmo_hold();
|
track_gizmo_hold();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1340,6 +1341,7 @@ void editor_mode::track_set_end()
|
|||||||
track_gizmo_settle();
|
track_gizmo_settle();
|
||||||
m_track_dirty = true;
|
m_track_dirty = true;
|
||||||
commit_track_drag(true);
|
commit_track_drag(true);
|
||||||
|
records_watch_end();
|
||||||
m_track_set_using = false;
|
m_track_set_using = false;
|
||||||
m_track_drag.clear();
|
m_track_drag.clear();
|
||||||
m_track_set_joints.clear();
|
m_track_set_joints.clear();
|
||||||
|
|||||||
@@ -607,6 +607,49 @@ void forget(int const Index)
|
|||||||
mark(layer);
|
mark(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<hit> on_record(int const Index, glm::dvec3 const &Point, double const Reach)
|
||||||
|
{
|
||||||
|
load();
|
||||||
|
if (Index < 0 || Index >= static_cast<int>(g_records.size()))
|
||||||
|
return std::nullopt;
|
||||||
|
return project(static_cast<std::size_t>(Index), plan_of(Point), Reach);
|
||||||
|
}
|
||||||
|
|
||||||
|
double cant_at(int const Index, double const Chainage)
|
||||||
|
{
|
||||||
|
load();
|
||||||
|
if (Index < 0 || Index >= static_cast<int>(g_records.size()))
|
||||||
|
return 0.0;
|
||||||
|
return alignment::evaluate(g_records[Index].result, Chainage).cant;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transform(int const Index, glm::dvec3 const &From, glm::dvec2 const &Fromdirection, glm::dvec3 const &To, glm::dvec2 const &Todirection)
|
||||||
|
{
|
||||||
|
load();
|
||||||
|
if (Index < 0 || Index >= static_cast<int>(g_records.size()))
|
||||||
|
return;
|
||||||
|
auto &entry{g_records[Index]};
|
||||||
|
auto const angle{geometry::signed_angle(glm::normalize(Fromdirection), glm::normalize(Todirection))};
|
||||||
|
auto const lift{To.y - From.y};
|
||||||
|
auto const place = [&](glm::dvec3 const &Point) {
|
||||||
|
auto const planar{plan_of(To) + geometry::turned(plan_of(Point) - plan_of(From), angle)};
|
||||||
|
return glm::dvec3{planar.x, Point.y + lift, planar.y};
|
||||||
|
};
|
||||||
|
auto &design{entry.design};
|
||||||
|
design.start = place(design.start);
|
||||||
|
design.end = place(design.end);
|
||||||
|
design.start_direction = geometry::turned(design.start_direction, angle);
|
||||||
|
design.end_direction = geometry::turned(design.end_direction, angle);
|
||||||
|
for (auto &vertex : design.vertices)
|
||||||
|
vertex.position = plan_of(place({vertex.position.x, 0.0, vertex.position.y}));
|
||||||
|
finish(entry);
|
||||||
|
entry.elements.clear();
|
||||||
|
for (auto const &e : entry.result.elements)
|
||||||
|
entry.elements.push_back(describe(e));
|
||||||
|
g_changed = true;
|
||||||
|
mark(entry.layer);
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<double> chainage_at(glm::dvec3 const &Point)
|
std::optional<double> chainage_at(glm::dvec3 const &Point)
|
||||||
{
|
{
|
||||||
auto const found{at(Point)};
|
auto const found{at(Point)};
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ int departed(std::vector<TTrack *> const &Tracks, double &Departure);
|
|||||||
// keeps the design in the file of the layer, in place of the one with the same ends
|
// keeps the design in the file of the layer, in place of the one with the same ends
|
||||||
int store(alignment::design const &Design, alignment::result const &Result, double const Origin, scene::layer_handle const Layer);
|
int store(alignment::design const &Design, alignment::result const &Result, double const Origin, scene::layer_handle const Layer);
|
||||||
void forget(int const Index);
|
void forget(int const Index);
|
||||||
|
// the point on the line of the stored alignment, if it lies by it within the reach
|
||||||
|
std::optional<hit> on_record(int const Index, glm::dvec3 const &Point, double const Reach);
|
||||||
|
// cant of the design at the chainage, mm
|
||||||
|
double cant_at(int const Index, double const Chainage);
|
||||||
|
// the stored alignment moved and turned in the plan the way the point and the direction were
|
||||||
|
void transform(int const Index, glm::dvec3 const &From, glm::dvec2 const &Fromdirection, glm::dvec3 const &To, glm::dvec2 const &Todirection);
|
||||||
// km of the point on the stored alignments, if it lies on one
|
// km of the point on the stored alignments, if it lies on one
|
||||||
std::optional<double> chainage_at(glm::dvec3 const &Point);
|
std::optional<double> chainage_at(glm::dvec3 const &Point);
|
||||||
// the records as they were before the changes made since the last call, if there were any; the current ones become the base
|
// the records as they were before the changes made since the last call, if there were any; the current ones become the base
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "editor/editorSwitchStore.hpp"
|
#include "editor/editorSwitchStore.hpp"
|
||||||
#include "editor/editorFormat.hpp"
|
#include "editor/editorFormat.hpp"
|
||||||
#include "editor/editorGeometry.hpp"
|
#include "editor/editorGeometry.hpp"
|
||||||
|
#include "editor/editorAlignmentStore.hpp"
|
||||||
|
|
||||||
#include "world/Track.h"
|
#include "world/Track.h"
|
||||||
#include "simulation/simulation.h"
|
#include "simulation/simulation.h"
|
||||||
@@ -39,7 +40,8 @@ bool g_loaded{false};
|
|||||||
|
|
||||||
// format of the lines, coordinates in the space of the file:
|
// format of the lines, coordinates in the space of the file:
|
||||||
// <switch|slip|crossing> <name> <type> <rail> <R> <n of 1:n> <hand L|R|-> <a> <b> <R of the main track, + right, - left, 0 straight>
|
// <switch|slip|crossing> <name> <type> <rail> <R> <n of 1:n> <hand L|R|-> <a> <b> <R of the main track, + right, - left, 0 straight>
|
||||||
// parts <count> <names>... start <x y z> dir <x z> km <km|-> number <label|-> source <designed|measured>
|
// parts <count> <names>... shape <main end along, across> <diverging end along, across> start <x y z> dir <x z>
|
||||||
|
// km <km|-> number <label|-> source <designed|measured>
|
||||||
std::string word(std::string const &Text)
|
std::string word(std::string const &Text)
|
||||||
{
|
{
|
||||||
if (Text.empty())
|
if (Text.empty())
|
||||||
@@ -69,6 +71,32 @@ bool in_place(record const &Record, TTrack const &Track)
|
|||||||
return geometry::plan_distance(Track.m_paths.front().points[segment_data::point::start], Record.start) <= kTolerance && glm::dot(direction_of(Track), Record.direction) > 0.9999;
|
return geometry::plan_distance(Track.m_paths.front().points[segment_data::point::start], Record.start) <= kTolerance && glm::dot(direction_of(Track), Record.direction) > 0.9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::dvec4 measure(TTrack const &Track)
|
||||||
|
{
|
||||||
|
auto const &main{Track.m_paths.front()};
|
||||||
|
auto const start{plan_of(main.points[segment_data::point::start])};
|
||||||
|
auto const along{direction_of(Track)};
|
||||||
|
glm::dvec2 const across{-along.y, along.x};
|
||||||
|
auto const local = [&](glm::dvec3 const &Point) {
|
||||||
|
auto const offset{plan_of(Point) - start};
|
||||||
|
return glm::dvec2{glm::dot(offset, along), glm::dot(offset, across)};
|
||||||
|
};
|
||||||
|
auto const mainend{local(main.points[segment_data::point::end])};
|
||||||
|
auto const branchend{Track.m_paths.size() > 1 ? local(Track.m_paths[1].points[segment_data::point::end]) : glm::dvec2{0.0}};
|
||||||
|
return {mainend.x, mainend.y, branchend.x, branchend.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool in_shape(record const &Record, TTrack const &Track)
|
||||||
|
{
|
||||||
|
if (false == Record.shaped)
|
||||||
|
return in_place(Record, Track);
|
||||||
|
auto const now{measure(Track)};
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
if (std::abs(now[i] - Record.shape[i]) > kTolerance)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void mark(scene::layer_handle const Layer)
|
void mark(scene::layer_handle const Layer)
|
||||||
{
|
{
|
||||||
if (false == scene::Layers.valid(Layer))
|
if (false == scene::Layers.valid(Layer))
|
||||||
@@ -89,6 +117,8 @@ void mark(scene::layer_handle const Layer)
|
|||||||
entry.parts.size())};
|
entry.parts.size())};
|
||||||
for (auto const &part : entry.parts)
|
for (auto const &part : entry.parts)
|
||||||
text += ' ' + word(part);
|
text += ' ' + word(part);
|
||||||
|
if (entry.shaped)
|
||||||
|
text += format(" shape %.4f %.4f %.4f %.4f", entry.shape.x, entry.shape.y, entry.shape.z, entry.shape.w);
|
||||||
text += format(" start %.4f %.4f %.4f dir %.9f %.9f km ", start.x, start.y, start.z, direction.x, direction.y);
|
text += format(" start %.4f %.4f %.4f dir %.9f %.9f km ", start.x, start.y, start.z, direction.x, direction.y);
|
||||||
text += entry.km.has_value() ? format("%.3f", *entry.km / 1000.0) : std::string{"-"};
|
text += entry.km.has_value() ? format("%.3f", *entry.km / 1000.0) : std::string{"-"};
|
||||||
text += " number " + word(entry.number) + " source " + word(entry.source);
|
text += " number " + word(entry.number) + " source " + word(entry.source);
|
||||||
@@ -135,7 +165,13 @@ void load()
|
|||||||
line >> part;
|
line >> part;
|
||||||
glm::dvec3 start{0.0}, ahead{0.0};
|
glm::dvec3 start{0.0}, ahead{0.0};
|
||||||
glm::dvec2 direction{0.0, 1.0};
|
glm::dvec2 direction{0.0, 1.0};
|
||||||
line >> keyword >> start.x >> start.y >> start.z >> keyword >> direction.x >> direction.y >> keyword >> km >> keyword >> entry.number >> keyword >> entry.source;
|
line >> keyword;
|
||||||
|
if (keyword == "shape")
|
||||||
|
{
|
||||||
|
line >> entry.shape.x >> entry.shape.y >> entry.shape.z >> entry.shape.w >> keyword;
|
||||||
|
entry.shaped = true;
|
||||||
|
}
|
||||||
|
line >> start.x >> start.y >> start.z >> keyword >> direction.x >> direction.y >> keyword >> km >> keyword >> entry.number >> keyword >> entry.source;
|
||||||
if (line.fail())
|
if (line.fail())
|
||||||
continue;
|
continue;
|
||||||
entry.start = context.to_world(start);
|
entry.start = context.to_world(start);
|
||||||
@@ -159,23 +195,51 @@ std::vector<record> const &records()
|
|||||||
return g_records;
|
return g_records;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<record> of(TTrack const &Track)
|
std::optional<record> named(TTrack const &Track)
|
||||||
{
|
{
|
||||||
load();
|
load();
|
||||||
auto const &name{Track.name()};
|
auto const &name{Track.name()};
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
for (auto const &entry : g_records)
|
for (auto const &entry : g_records)
|
||||||
{
|
if (std::find(entry.parts.begin(), entry.parts.end(), name) != entry.parts.end())
|
||||||
if (std::find(entry.parts.begin(), entry.parts.end(), name) == entry.parts.end())
|
|
||||||
continue;
|
|
||||||
auto const *first{usable(entry.parts.front())};
|
|
||||||
if (first != nullptr && in_place(entry, *first))
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<record> of(TTrack const &Track)
|
||||||
|
{
|
||||||
|
auto const found{named(Track)};
|
||||||
|
if (false == found.has_value())
|
||||||
|
return std::nullopt;
|
||||||
|
auto const *first{usable(found->parts.front())};
|
||||||
|
if (first == nullptr || false == in_shape(*found, *first))
|
||||||
|
return std::nullopt;
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> follow()
|
||||||
|
{
|
||||||
|
load();
|
||||||
|
std::vector<std::string> moved;
|
||||||
|
std::set<scene::layer_handle> layers;
|
||||||
|
for (auto &entry : g_records)
|
||||||
|
{
|
||||||
|
auto const *first{usable(entry.parts.front())};
|
||||||
|
if (first == nullptr || false == entry.shaped || false == in_shape(entry, *first) || in_place(entry, *first))
|
||||||
|
continue;
|
||||||
|
entry.start = first->m_paths.front().points[segment_data::point::start];
|
||||||
|
entry.direction = direction_of(*first);
|
||||||
|
entry.km = alignment_store::chainage_at(entry.start);
|
||||||
|
moved.push_back(entry.name);
|
||||||
|
layers.insert(entry.layer);
|
||||||
|
}
|
||||||
|
for (auto const layer : layers)
|
||||||
|
mark(layer);
|
||||||
|
g_changed = g_changed || false == moved.empty();
|
||||||
|
return moved;
|
||||||
|
}
|
||||||
|
|
||||||
double branch_radius(record const &Record)
|
double branch_radius(record const &Record)
|
||||||
{
|
{
|
||||||
if (Record.radius <= 0.0)
|
if (Record.radius <= 0.0)
|
||||||
@@ -188,6 +252,11 @@ double branch_radius(record const &Record)
|
|||||||
void put(record Entry, scene::layer_handle const Layer)
|
void put(record Entry, scene::layer_handle const Layer)
|
||||||
{
|
{
|
||||||
load();
|
load();
|
||||||
|
if (auto const *first{usable(Entry.parts.empty() ? std::string{} : Entry.parts.front())})
|
||||||
|
{
|
||||||
|
Entry.shape = measure(*first);
|
||||||
|
Entry.shaped = true;
|
||||||
|
}
|
||||||
auto const existing{std::find_if(g_records.begin(), g_records.end(), [&](record const &Other) { return Other.name == Entry.name && Other.kind == Entry.kind; })};
|
auto const existing{std::find_if(g_records.begin(), g_records.end(), [&](record const &Other) { return Other.name == Entry.name && Other.kind == Entry.kind; })};
|
||||||
if (existing != g_records.end())
|
if (existing != g_records.end())
|
||||||
{
|
{
|
||||||
@@ -222,6 +291,7 @@ void forget(std::string const &Name)
|
|||||||
void tidy()
|
void tidy()
|
||||||
{
|
{
|
||||||
load();
|
load();
|
||||||
|
follow();
|
||||||
std::set<scene::layer_handle> layers;
|
std::set<scene::layer_handle> layers;
|
||||||
for (auto &entry : g_records)
|
for (auto &entry : g_records)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ struct record
|
|||||||
std::vector<std::string> parts; // the switch, the switches of a slip, the paths of a crossing
|
std::vector<std::string> parts; // the switch, the switches of a slip, the paths of a crossing
|
||||||
glm::dvec3 start{0.0}; // of the first part
|
glm::dvec3 start{0.0}; // of the first part
|
||||||
glm::dvec2 direction{0.0, 1.0};
|
glm::dvec2 direction{0.0, 1.0};
|
||||||
|
// ends of the main and the diverging track of the first part seen from its start: along, across, along, across. it stays the
|
||||||
|
// same as long as the switch is moved or turned as a whole, it changes when the switch gets bent out of its shape
|
||||||
|
glm::dvec4 shape{0.0};
|
||||||
|
bool shaped{false};
|
||||||
std::optional<double> km;
|
std::optional<double> km;
|
||||||
std::string number{"-"};
|
std::string number{"-"};
|
||||||
std::string source{"designed"}; // designed: from the catalogue, measured: copied from a switch of the scenery
|
std::string source{"designed"}; // designed: from the catalogue, measured: copied from a switch of the scenery
|
||||||
@@ -46,8 +50,12 @@ struct record
|
|||||||
void reset();
|
void reset();
|
||||||
void load();
|
void load();
|
||||||
std::vector<record> const &records();
|
std::vector<record> const &records();
|
||||||
// the record of the switch, slip or crossing the track is a part of, while its first part starts where the record says
|
// the record of the switch, slip or crossing the track is a part of, while its first part keeps the shape the record says
|
||||||
std::optional<record> of(TTrack const &Track);
|
std::optional<record> of(TTrack const &Track);
|
||||||
|
// the record of the track by its name alone, also when the switch lost its shape
|
||||||
|
std::optional<record> named(TTrack const &Track);
|
||||||
|
// records whose switches were moved or turned as a whole take their new place and km; returns their names
|
||||||
|
std::vector<std::string> follow();
|
||||||
// radius of the diverging track: of the type, bent with the main track for an arc switch
|
// radius of the diverging track: of the type, bent with the main track for an arc switch
|
||||||
double branch_radius(record const &Record);
|
double branch_radius(record const &Record);
|
||||||
// keeps the record in the file of the layer, in place of the one with the same name
|
// keeps the record in the file of the layer, in place of the one with the same name
|
||||||
|
|||||||
@@ -5379,3 +5379,15 @@ msgstr "Kilometraż początku rozjazdu; brany z planu sytuacyjnego zapisanego w
|
|||||||
|
|
||||||
msgid "Slip switches and crossings"
|
msgid "Slip switches and crossings"
|
||||||
msgstr "Rozjazdy krzyżowe i skrzyżowania"
|
msgstr "Rozjazdy krzyżowe i skrzyżowania"
|
||||||
|
|
||||||
|
msgid "The kept design of the line went along with its paths"
|
||||||
|
msgstr "Zapisany projekt linii przesunął się razem z jej odcinkami"
|
||||||
|
|
||||||
|
msgid "%d path(s) left the design kept in %s, by up to %.2f m: Ctrl+Z takes it back, the route design lays them by the design again or forgets it"
|
||||||
|
msgstr "Odcinki (%d) zeszły z projektu zapisanego w %s, maks. o %.2f m: Ctrl+Z cofa, projekt trasy ułoży je ponownie według projektu albo go zapomni"
|
||||||
|
|
||||||
|
msgid "The cant differs from the kept design by up to %.0f mm"
|
||||||
|
msgstr "Przechyłka różni się od zapisanego projektu maks. o %.0f mm"
|
||||||
|
|
||||||
|
msgid "Switch %s lost the shape of its type %s: Ctrl+Z takes it back"
|
||||||
|
msgstr "Rozjazd %s stracił kształt swojego typu %s: Ctrl+Z cofa"
|
||||||
|
|||||||
Reference in New Issue
Block a user