From d090e93c812078fb5590a2754e2908fb641b6610 Mon Sep 17 00:00:00 2001 From: maj00r Date: Thu, 22 Oct 2026 19:51:55 +0200 Subject: [PATCH] fix(editor): a block boundary drawn places its signal across only where the other track runs near, the hover and the click count the block signals facing the trains alike, an SHP resonator at a joint finds the piece of a track cut for another one, and a batch of signals missing its template changes nothing but the tracks cut, Ctrl+Z taking them back; the km of each line kept for the hover, the shorter block section named in its warning, the block column wider --- application/editormodesignal.cpp | 7 +++++ application/editormodesrk.cpp | 52 ++++++++++++++++++++------------ application/editormodesrk.h | 2 ++ lang/editor_pl.po | 15 +++++---- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/application/editormodesignal.cpp b/application/editormodesignal.cpp index 2261dd47..7b875f04 100644 --- a/application/editormodesignal.cpp +++ b/application/editormodesignal.cpp @@ -980,6 +980,13 @@ std::size_t editor_mode::signal_batch(signal_changes const &Changes, std::vector items.push_back(std::move(placing)); reads.emplace_back(spot, variant->read.empty() ? std::string{} : editor_includes::substitute(variant->read, {order.name})); } + if (false == Error.empty()) + { + // nothing changed but the tracks cut for them, a step of undo + if (false == States.empty() || false == Created.empty()) + push_track_snapshot(std::move(States), std::move(Created)); + return 0; + } // the names passed round among the signals go through ones of their own first, or a read event renamed would be renamed again items.insert(items.end(), Changes.others.begin(), Changes.others.end()); EditorSnapshot step; diff --git a/application/editormodesrk.cpp b/application/editormodesrk.cpp index 7cc5e399..34661098 100644 --- a/application/editormodesrk.cpp +++ b/application/editormodesrk.cpp @@ -668,6 +668,17 @@ std::unordered_set guarded(std::vector const &Co return result; } +// a block signal standing by the track of the line facing its trains, Distance: how far out along it +bool block_along(station::line const &Line, standing_signal const &Signal, double &Distance) +{ + double gap{0.0}; + Distance = station::distance_on(Line, Signal.position, gap); + if (Signal.kind != "block" || gap > 4.5 || Distance < 50.0 || Distance > Line.length() - 1.0) + return false; + auto const way{station::point_on(Line, Distance).way}; + return (Line.inbound ? -1.0 : 1.0) * glm::dot(travel_of(Signal.yaw), glm::dvec2{way.x, way.z}) >= 0.87; +} + } // namespace srk_tool::shp_state srk_tool::head_check::shp_of() const @@ -1335,9 +1346,9 @@ void srk_tool::render_lines() auto changed{false}; if (ImGui::BeginTable("##srklinelist", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp)) { - ImGui::TableSetupColumn(STR_C("Line"), ImGuiTableColumnFlags_WidthStretch, 0.27f); - ImGui::TableSetupColumn(STR_C("To"), ImGuiTableColumnFlags_WidthStretch, 0.33f); - ImGui::TableSetupColumn(STR_C("Block"), ImGuiTableColumnFlags_WidthStretch, 0.40f); + ImGui::TableSetupColumn(STR_C("Line"), ImGuiTableColumnFlags_WidthStretch, 0.26f); + ImGui::TableSetupColumn(STR_C("To"), ImGuiTableColumnFlags_WidthStretch, 0.29f); + ImGui::TableSetupColumn(STR_C("Block"), ImGuiTableColumnFlags_WidthStretch, 0.45f); ImGui::TableHeadersRow(); for (std::size_t index = 0; index < m_lines.size() && false == changed; ++index) { @@ -1481,7 +1492,7 @@ std::string srk_tool::boundary_hover(glm::dvec3 const &Point, bool &Valid) m_boundary.point = station::point_on(line, at).point; // the other track across, the block signals standing within reach on both std::vector> tracks{{static_cast(best), at}}; - if (row.partner >= 0 && row.partner < static_cast(m_line_ways.size())) + if (row.partner >= 0 && row.partner < static_cast(std::min(m_lines.size(), m_line_ways.size())) && false == m_lines[row.partner].legacy && m_lines[row.partner].block != block_kind::semi) if (double gap{0.0}; true) if (auto const across{station::distance_on(m_line_ways[row.partner], m_boundary.point, gap)}; gap < 12.0) tracks.emplace_back(static_cast(row.partner), across); @@ -1517,10 +1528,9 @@ std::string srk_tool::boundary_hover(glm::dvec3 const &Point, bool &Valid) continue; } auto const place{station::point_on(way, distance)}; - auto const number{km_line(way)}; m_boundary.places.push_back(place.point); m_boundary.ways.push_back(place.way); - m_boundary.names.push_back(station::block_number(km_along(way, number, distance), way.number, km_rising(way, number))); + m_boundary.names.push_back(station::block_number(km_along(way, other.km_number, distance), way.number, other.rising)); } std::string names; for (auto const &name : m_boundary.names) @@ -1532,7 +1542,7 @@ std::string srk_tool::boundary_hover(glm::dvec3 const &Point, bool &Valid) auto const least{row.block == block_kind::four ? row.braking * 0.5 : row.braking}; auto label{format(STR_C("Click: block signals %s here: the block sections %.2f km and %.2f km"), names.c_str(), (at - previous) / 1000.0, (next - at) / 1000.0)}; if (std::min(at - previous, next - at) < least) - label += "\n" + format(row.block == block_kind::four ? STR_C("shorter than half the braking distance, %.0f m, of the 4-aspect block") : STR_C("shorter than the braking distance, %.0f m"), least); + label += "\n" + format(row.block == block_kind::four ? STR_C("The block section of %.2f km is shorter than half the braking distance, %.0f m, of the 4-aspect block") : STR_C("The block section of %.2f km is shorter than the braking distance, %.0f m"), std::min(at - previous, next - at) / 1000.0, least); return label; } @@ -2408,9 +2418,10 @@ void srk_tool::set_signals() } } std::string error; + auto const touched{false == before.empty() || false == created.empty()}; auto const count{m_signals.signal_batch({placed, renamed, {}, {}, {}}, std::move(before), std::move(created), error)}; if (false == error.empty()) - m_status = format(STR_C("The signals couldn't be placed: %s"), error.c_str()); + m_status = format(STR_C("The signals couldn't be placed: %s"), error.c_str()) + (touched ? ". " + STR("Ctrl+Z takes back the tracks cut") : std::string{}); else m_status = format(STR_P("%zu signal placed", "%zu signals placed", count), count) + ", " + format(STR_P("%zu renamed", "%zu renamed", renamed.size()), renamed.size()); if (false == unfit.empty()) @@ -2590,12 +2601,13 @@ void srk_tool::survey_lines(std::vector const &Standing) row.travel = travel_of(Standing[owners[line.entry]].yaw); row.block = block_of(line, row.entry, Standing, heads, row.why, row.own, row.own_why, row.blocks); row.braking = line_braking(line); + row.km_number = km_line(line); + row.rising = km_rising(line, row.km_number); auto switched{false}; for (auto const &signal : Standing) { - double gap{0.0}; - auto const distance{station::distance_on(line, signal.position, gap)}; - if (signal.kind != "block" || gap > 4.5 || distance < 50.0 || distance > line.length() - 1.0) + double distance{0.0}; + if (false == block_along(line, signal, distance)) continue; row.stops.emplace_back(distance, signal_shown(signal.name, stem)); switched = switched || guards.count(ToLower(signal.name)) > 0; @@ -2666,11 +2678,8 @@ void srk_tool::set_lines(block_edit const *Edit) auto switched{false}; for (std::size_t k = 0; k < standing.size(); ++k) { - if (standing[k].kind != "block") - continue; - double gap{0.0}; - auto const distance{station::distance_on(line, standing[k].position, gap)}; - if (gap > 4.5 || distance < 50.0 || distance > line.length() - 1.0 || (line.inbound ? -1.0 : 1.0) * facing_out(line, standing[k], distance) < 0.87) + double distance{0.0}; + if (false == block_along(line, standing[k], distance)) continue; along[index].push_back(k); switched = switched || guards.count(ToLower(standing[k].name)) > 0; @@ -2702,7 +2711,10 @@ void srk_tool::set_lines(block_edit const *Edit) } processed[edited] = 1; if (auto const partner{lines[edited].partner}; partner >= 0 && automatic[partner] == 1) - processed[partner] = 1; + { + station::distance_on(lines[partner], station::point_on(lines[edited], drawn).point, gap); + processed[partner] = gap < 12.0 ? 1 : 0; + } } auto const described{line_of_open()}; double known{0.0}; @@ -3197,10 +3209,11 @@ void srk_tool::set_lines(block_edit const *Edit) return; } std::string error; + auto const touched{false == before.empty() || false == created.empty()}; m_signals.signal_batch(changes, std::move(before), std::move(created), error); if (false == error.empty()) { - m_status = format(STR_C("The signals couldn't be placed: %s"), error.c_str()); + m_status = format(STR_C("The signals couldn't be placed: %s"), error.c_str()) + (touched ? ". " + STR("Ctrl+Z takes back the tracks cut") : std::string{}); return; } m_status = format(STR_P("%zu block signal placed", "%zu block signals placed", blocks), blocks) + ", " + format(STR_P("%zu warning disc", "%zu warning discs", discs), discs) + ", " + @@ -3224,6 +3237,7 @@ void srk_tool::survey_signals() m_heads.clear(); m_heads_known = false; m_lines.clear(); + m_line_ways.clear(); m_lines_problem = STR("Looking for the signal templates..."); if (false == m_measured) measure({}); @@ -3642,7 +3656,7 @@ void srk_tool::set_shp() signal_changes changes; for (auto const &entry : places) { - auto *track{entry.track != nullptr ? entry.track : piece_at(entry.cut, entry.inside)}; + auto *track{entry.track != nullptr ? piece_at(entry.track, entry.point) : piece_at(entry.cut, entry.inside)}; // the trains run into the track at the point: at the start of its path running towards its end if (glm::distance(track->m_paths.front().points[entry.facing > 0 ? segment_data::point::start : segment_data::point::end], entry.point) > 1.0) { diff --git a/application/editormodesrk.h b/application/editormodesrk.h index 73810cf6..89399483 100644 --- a/application/editormodesrk.h +++ b/application/editormodesrk.h @@ -201,6 +201,8 @@ class srk_tool final : public editor_tool // block signals stand along it, none switched by block sections of the editor: it keeps the block of the scenery as it stands bool legacy{false}; double braking{0.0}; // m, the braking distance on it + std::string km_number; // the line of the kilometrage it runs along + bool rising{true}; // its trains run towards the higher km // the signals of the other block standing along it: warning discs on a line of the automatic block, block signals on one of the // semi-automatic one, the first of them std::size_t leftovers{0}; diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 6b5d7ab3..5993edaa 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -11246,10 +11246,10 @@ msgid "LMB: fly to the first of them" msgstr "LPM: leć do pierwszego z nich" msgid "SBL, 3 aspects" -msgstr "SBL trzystawna" +msgstr "SBL 3-stawna" msgid "SBL, 4 aspects" -msgstr "SBL czterostawna" +msgstr "SBL 4-stawna" msgid "Automatic block, 3 aspects (SBL)" msgstr "Samoczynna blokada liniowa trzystawna (SBL)" @@ -11302,11 +11302,14 @@ msgstr "Klik: usuń semafory SBL %s, odstępy po obu stronach połączone: %.2f msgid "Click: block signals %s here: the block sections %.2f km and %.2f km" msgstr "Klik: semafory SBL %s tutaj, odstępy %.2f km i %.2f km" -msgid "shorter than half the braking distance, %.0f m, of the 4-aspect block" -msgstr "krótszy niż połowa drogi hamowania (%.0f m), a to SBL czterostawna" +msgid "The block section of %.2f km is shorter than half the braking distance, %.0f m, of the 4-aspect block" +msgstr "Odstęp %.2f km jest krótszy niż połowa drogi hamowania (%.0f m) przy SBL czterostawnej" -msgid "shorter than the braking distance, %.0f m" -msgstr "krótszy niż droga hamowania, %.0f m" +msgid "The block section of %.2f km is shorter than the braking distance, %.0f m" +msgstr "Odstęp %.2f km jest krótszy niż droga hamowania (%.0f m)" + +msgid "Ctrl+Z takes back the tracks cut" +msgstr "Ctrl+Z cofa przecięcia torów" msgid "The line drawn on isn't there any more" msgstr "Szlaku, na którym rysujesz, już nie ma"