From 9855de74b4c1e2c3278bebbc0732854685e625c6 Mon Sep 17 00:00:00 2001 From: maj00r Date: Sat, 24 Oct 2026 20:05:04 +0200 Subject: [PATCH] feat(editor): the tracks are laid to the PKP PLK norms only: the choice of the free laying is gone, its cards in the panels of the laying and of the plan, the question as the laying starts and the setting; the transition curves and the cant of the norms always, the speed of the laying with its chips, the radius below the minimum for the speed a warning. The settings keep the radii the bends of the straights will be eased with instead --- application/editormode.cpp | 14 -- application/editormode.h | 14 +- application/editormodelay.cpp | 198 ++----------------------- application/editormodenmt.cpp | 2 +- application/editormoderoute.cpp | 3 - application/editormodeselftest.cpp | 2 - application/editormodeselftestjoin.cpp | 8 +- application/editormodestraights.cpp | 3 +- application/editormodetrack.cpp | 13 +- editor/editorSettings.cpp | 16 +- editor/editorSettings.hpp | 18 +-- 11 files changed, 43 insertions(+), 248 deletions(-) diff --git a/application/editormode.cpp b/application/editormode.cpp index 04cfc07a..c49931a0 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -657,7 +657,6 @@ bool editor_mode::init() { EditorSettings.load(); Global.EditorOrthoTracks = EditorSettings.top_tracks(); - set_norms_free(EditorSettings.norms() == editorSettings::track_norms::free_laying); EditorModelSets.load(); EditorTrackPresets.load(); Camera.Init({0, 15, 0}, {glm::radians(-30.0), glm::radians(180.0), 0}, nullptr); @@ -1598,7 +1597,6 @@ bool editor_mode::update() render_open_scenery_popup(); render_shortcuts_window(); render_first_steps(); - render_norms_prompt(); render_nmt_prompt(); render_nmt_banner(); render_orthophoto_window(); @@ -1641,18 +1639,6 @@ void editor_mode::render_settings() ImGui::Separator(); ImGui::Checkbox(STR_C("Transform gizmo (ImGuizmo)"), &m_gizmo_enabled); - ImGui::Separator(); - ImGui::TextUnformatted(STR_C("Laying of new tracks")); - const char *norms[] = {STR_C("Ask as the laying starts"), STR_C("Free laying"), STR_C("To the PKP PLK norms")}; - int chosen = static_cast(EditorSettings.norms()); - if (ImGui::Combo("##tracknorms", &chosen, norms, IM_ARRAYSIZE(norms))) - { - EditorSettings.norms(static_cast(chosen)); - EditorSettings.save(); - if (chosen > 0) - set_norms_free(chosen == 1); - } - ImGui::Separator(); ImGui::TextUnformatted(STR_C("Colours of the editor")); const char *palettes[] = {STR_C("Green, as the rest of the simulator"), STR_C("Amber, of the editor")}; diff --git a/application/editormode.h b/application/editormode.h index 0d32e7da..3cf5732b 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1070,7 +1070,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri void render_route_stored(); void route_update() { - m_route.design.norms.checked = false == m_norms_free; + m_route.design.norms.checked = true; m_route.result = alignment::compute(m_route.design); } void route_apply(); @@ -1396,7 +1396,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri std::string preview_error; double preview_length{0.0}; double radius{500.0}; - bool transitions{false}; double piece_length{100.0}; bool copy_selected{false}; editor_track::path_style style; @@ -1413,16 +1412,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri std::size_t history{0}; // the step of the history the chain was begun at }; lay_tool m_lay; - bool m_norms_free{false}; - // the choice between the free laying and the norms, asked once a session as the laying or the plan is opened first - bool m_norms_prompt{false}; - bool m_norms_asked{false}; - bool m_norms_remember{false}; alignment::limits laying_norms() const; - // returns: a card was clicked - bool render_norms_choice(); - void render_norms_prompt(); - void set_norms_free(bool const Free); glm::dvec3 lay_angle_snap(glm::dvec3 const &Mouse, std::string &Label) const; // the straight track Alt turns the laid straight to: the nearest one the straight from From to To crosses, or one along From TTrack const *skew_reference(glm::dvec3 const &From, glm::dvec3 const &To, double const Reach) const; @@ -1546,7 +1536,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri TTrack const *m_join_track{nullptr}; editor_track::point_ref m_join_point; mutable alignment::join_result m_join_last; - // the layout laid on from the end of From with the transition curves of the norms; none in the free laying, or where it doesn't fit + // the layout laid on from the end of From with the transition curves of the norms; none where it doesn't fit std::optional eased_layout(TTrack const *From, glm::dvec3 const &Point, glm::dvec2 const &Direction, glm::dvec3 const &Target, double const Radius) const; mutable std::optional m_eased_last; mutable std::optional>> m_eased_cache; diff --git a/application/editormodelay.cpp b/application/editormodelay.cpp index 65877b5e..f36db193 100644 --- a/application/editormodelay.cpp +++ b/application/editormodelay.cpp @@ -426,7 +426,7 @@ void editor_mode::point_drag_finish() std::optional editor_mode::eased_layout(TTrack const *From, glm::dvec3 const &Point, glm::dvec2 const &Direction, glm::dvec3 const &Target, double const Radius) const { m_eased_last.reset(); - if (false == m_lay.transitions || From == nullptr || From->eType != tt_Normal) + if (From == nullptr || From->eType != tt_Normal) return std::nullopt; auto const end{editor_track::bend_at(*From, Point)}; if (false == end.has_value()) @@ -571,13 +571,13 @@ std::vector editor_mode::join_pieces(TTrack const *From, editor_tr request.end.roll = End.track != nullptr ? editor_track::joint_roll(*End.track, End.point) : 0.0; request.radius = m_join_radius; request.variant = m_join_variant; - request.transitions = m_lay.transitions; + request.transitions = true; request.speed = design_speed(From, End.track); request.kink = m_joints.kink_angle() * 0.5; request.shape = m_route.design.shape; request.norms = laying_norms(); auto result{alignment::join(request)}; - if (m_lay.transitions && result.kind != alignment::join_kind::straight && result.kind != alignment::join_kind::arc && glm::length(request.end.direction) > 1e-9) + if (result.kind != alignment::join_kind::straight && result.kind != alignment::join_kind::arc && glm::length(request.end.direction) > 1e-9) { auto const grade{(End.position.y - Start.y) / std::max(1.0, plan_distance(Start, End.position))}; auto const in{From != nullptr && From->eType == tt_Normal ? editor_track::ease_out_of(*From, Start, grade, request.speed, request.norms) : editor_track::easing{}}; @@ -989,8 +989,8 @@ std::vector editor_mode::lay_pieces(std::vector const result.pieces.clear(); return result; }; - auto const in{tool.transitions ? eased(tool.start, 0.0, 1.0) : editor_track::easing{}}; - auto const out{tool.transitions ? eased(End, shape.length, -1.0) : editor_track::easing{}}; + auto const in{eased(tool.start, 0.0, 1.0)}; + auto const out{eased(End, shape.length, -1.0)}; if ((false == in.pieces.empty() || false == out.pieces.empty()) && editor_track::eases_room(in, out, Points.front(), design.start_direction, Points.back(), design.end_direction)) { auto points{Points}; @@ -1063,7 +1063,7 @@ alignment::result editor_mode::lay_shape(std::vector const &Points, design.vertices.back().offset = std::max(1.0, glm::dot(plan_of(Points.back() - Points[Points.size() - 2]), design.end_direction)); } } - return alignment::compute_recommended(design, tool.transitions); + return alignment::compute_recommended(design, true); } void editor_mode::lay_click() @@ -1360,202 +1360,26 @@ editor_mode::track_hover editor_mode::split_spot() const alignment::limits editor_mode::laying_norms() const { auto norms{m_route.design.norms}; - norms.checked = false == m_norms_free; + norms.checked = true; return norms; } -namespace -{ - -// a card of the geometry of the new track: its plan, and under it its curvature along the length, a point running along both; -// a plain arc jumps to its curvature, a railway curve leads into it along a transition, the cant with it -float geometry_card_height(char const *Title, char const *Text, float const Width) -{ - auto const font{ImGui::GetFontSize()}; - auto const pad{std::round(font * 0.5f)}; - auto const wrap{Width - 2.0f * pad}; - return pad + ImGui::CalcTextSize(Title, nullptr, false, wrap).y + pad * 0.5f + std::round(font * 2.6f) + pad * 0.5f + ImGui::CalcTextSize(Text, nullptr, false, wrap).y + pad; -} - -bool geometry_card(char const *Id, char const *Title, char const *Text, bool const Railway, bool const Chosen, float const Width, float const Height) -{ - auto const font{ImGui::GetFontSize()}; - auto const pad{std::round(font * 0.5f)}; - auto const sketch{std::round(font * 2.6f)}; - auto const wrap{Width - 2.0f * pad}; - auto const title{ImGui::CalcTextSize(Title, nullptr, false, wrap)}; - auto const height{Height}; - auto const top{ImGui::GetCursorScreenPos()}; - auto const clicked{ImGui::InvisibleButton(Id, ImVec2(Width, height))}; - auto const hovered{ImGui::IsItemHovered()}; - auto *list{ImGui::GetWindowDrawList()}; - auto const accent{family_colour(0)}; - ImVec2 const bottom{top.x + Width, top.y + height}; - auto const rounding{std::round(font * 0.35f)}; - list->AddRectFilled(top, bottom, Chosen ? (accent & ~IM_COL32_A_MASK) | IM_COL32(0, 0, 0, 46) : ImGui::GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), rounding); - list->AddRect(top, bottom, Chosen ? accent : ImGui::GetColorU32(ImGuiCol_Border), rounding, 0, Chosen ? 2.0f : 1.0f); - auto y{top.y + pad}; - list->AddText(nullptr, 0.0f, ImVec2(top.x + pad, y), ImGui::GetColorU32(ImGuiCol_Text), Title, nullptr, wrap); - y += title.y + pad * 0.5f; - // the curvature along the length, as a share of the curvature of the arc - auto const curvature = [Railway](double const Share) { - if (Railway) - return std::clamp((Share - 0.22) / 0.3, 0.0, 1.0); - return Share < 0.37 ? 0.0 : 1.0; - }; - int constexpr steps{80}; - std::vector plan; - plan.reserve(steps + 1); - double heading{0.0}, px{0.0}, py{0.0}; - auto const turn{1.45 / (Railway ? 0.63 - 0.15 : 0.63)}; - for (int i = 0; i <= steps; ++i) - { - plan.emplace_back(static_cast(px), static_cast(py)); - auto const share{(i + 0.5) / steps}; - heading += curvature(share) * turn / steps; - px += std::cos(heading) / steps; - py -= std::sin(heading) / steps; - } - ImVec2 low{plan.front()}, high{plan.front()}; - for (auto const &point : plan) - { - low = ImVec2(std::min(low.x, point.x), std::min(low.y, point.y)); - high = ImVec2(std::max(high.x, point.x), std::max(high.y, point.y)); - } - // the plan on the left, the curvature along the length on the right - auto const half{std::floor((wrap - pad) * 0.5f)}; - auto const scale{std::min(half / std::max(1e-3f, high.x - low.x), sketch / std::max(1e-3f, high.y - low.y))}; - ImVec2 const origin{top.x + pad + (half - (high.x - low.x) * scale) * 0.5f, y + sketch - (high.y - low.y) * scale}; - for (auto &point : plan) - point = ImVec2(origin.x + (point.x - low.x) * scale, origin.y + (point.y - low.y) * scale); - auto const line{Chosen ? accent : ImGui::GetColorU32(ImGuiCol_Text, 0.75f)}; - list->AddPolyline(plan.data(), static_cast(plan.size()), line, 0, 2.0f); - auto const label{ImGui::CalcTextSize("1/R")}; - auto const graph_left{top.x + pad + half + pad * 0.5f + label.x + 2.0f}; - auto const graph_width{top.x + pad + wrap - graph_left}; - auto const graph_top{y}; - auto const graph{sketch}; - auto const axis{ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.6f)}; - list->AddLine(ImVec2(graph_left, graph_top + graph), ImVec2(graph_left + graph_width, graph_top + graph), axis); - list->AddLine(ImVec2(graph_left, graph_top), ImVec2(graph_left, graph_top + graph), axis); - list->AddText(ImVec2(graph_left - label.x - 2.0f, graph_top + graph * 0.2f - label.y * 0.5f), axis, "1/R"); - std::vector curve; - for (int i = 0; i <= steps; ++i) - { - auto const share{static_cast(i) / steps}; - curve.emplace_back(graph_left + static_cast(share) * graph_width, graph_top + graph - static_cast(curvature(share)) * graph * 0.8f); - } - list->AddPolyline(curve.data(), static_cast(curve.size()), line, 0, 1.5f); - if (Railway) - for (int i = 0; i < steps; i += 4) - { - auto const share{static_cast(i) / steps}; - auto const next{static_cast(i + 2) / steps}; - list->AddLine(ImVec2(graph_left + static_cast(share) * graph_width, graph_top + graph - static_cast(curvature(share)) * graph * 0.45f), - ImVec2(graph_left + static_cast(next) * graph_width, graph_top + graph - static_cast(curvature(next)) * graph * 0.45f), IM_COL32(240, 170, 60, 220), 1.0f); - } - auto const running{std::fmod(ImGui::GetTime() * 0.22, 1.0)}; - auto const index{std::clamp(static_cast(running * steps), 0, steps)}; - list->AddCircleFilled(plan[index], 3.0f, IM_COL32(255, 255, 255, 230)); - list->AddLine(ImVec2(curve[index].x, graph_top), ImVec2(curve[index].x, graph_top + graph), IM_COL32(255, 255, 255, 70)); - list->AddCircleFilled(curve[index], 2.5f, IM_COL32(255, 255, 255, 230)); - y += sketch + pad * 0.5f; - list->AddText(nullptr, 0.0f, ImVec2(top.x + pad, y), ImGui::GetColorU32(ImGuiCol_TextDisabled), Text, nullptr, wrap); - return clicked; -} - -} // namespace - -bool editor_mode::render_norms_choice() -{ - auto picked{false}; - auto const gap{std::round(ImGui::GetFontSize() * 0.5f)}; - auto const width{std::floor((ImGui::GetContentRegionAvail().x - gap) * 0.5f)}; - char const *const titles[]{STR_C("Free laying"), STR_C("To the PKP PLK norms")}; - char const *const texts[]{STR_C("Plain arcs, no transition curves nor cant"), STR_C("Transition curves and cant for the speed, checked against the norms")}; - auto const height{std::max(geometry_card_height(titles[0], texts[0], width), geometry_card_height(titles[1], texts[1], width))}; - ImGui::PushID("geometry"); - for (int i = 0; i < 2; ++i) - { - if (i > 0) - ImGui::SameLine(0.0f, gap); - auto const chosen{m_norms_free == (i == 0)}; - auto const clicked{geometry_card(i == 0 ? "##free" : "##norms", titles[i], texts[i], i == 1, chosen, width, height)}; - item_tooltip(i == 0 ? "Plain arcs with no transition curves and no cant, no warnings about the norms: the track goes where it's clicked" - : "Transition curves and cant for the design speed, warnings when the radius, the cant or the transitions don't meet the norms"); - picked |= clicked; - if (clicked && false == chosen) - { - set_norms_free(i == 0); - // a kept choice follows the one made later - if (EditorSettings.norms() != editorSettings::track_norms::ask) - { - EditorSettings.norms(m_norms_free ? editorSettings::track_norms::free_laying : editorSettings::track_norms::plk); - EditorSettings.save(); - } - } - } - ImGui::PopID(); - return picked; -} - -void editor_mode::render_norms_prompt() -{ - if (false == m_norms_prompt) - return; - char const *const title{STR_C("How to lay the tracks###normsprompt")}; - if (false == ImGui::IsPopupOpen(title)) - ImGui::OpenPopup(title); - ImGui::SetNextWindowSize(ImVec2(520.0f * Global.ui_scale, 0.0f)); - if (false == ImGui::BeginPopupModal(title, nullptr, ImGuiWindowFlags_NoResize)) - return; - ImGui::TextWrapped("%s", STR_C("Choose how the new tracks are laid. It can be changed any time at the top of the panels of laying and of the plan.")); - ImGui::Spacing(); - if (render_norms_choice()) - { - if (m_norms_remember) - { - EditorSettings.norms(m_norms_free ? editorSettings::track_norms::free_laying : editorSettings::track_norms::plk); - EditorSettings.save(); - } - m_norms_prompt = false; - ImGui::CloseCurrentPopup(); - } - ImGui::Spacing(); - ImGui::Checkbox(STR_C("Remember the choice, don't ask again"), &m_norms_remember); - item_tooltip("Asking again can be switched on in the settings of the editor (General)"); - ImGui::EndPopup(); -} - -void editor_mode::set_norms_free(bool const Free) -{ - m_norms_free = Free; - m_lay.transitions = false == m_norms_free; - if (false == m_route.chain.tracks.empty()) - route_update(); -} - void editor_mode::render_lay_ui() { auto &tool{m_lay}; - render_norms_choice(); - ImGui::Separator(); ImGui::PushItemWidth(120.0f); ImGui::DragScalar(STR_C("Curve radius (m)"), ImGuiDataType_Double, &tool.radius, 5.0f, nullptr, nullptr, "%.0f"); item_tooltip("Drag to change, Ctrl+click to type the value. While laying: Ctrl+wheel"); value_chips("radii", tool.radius, {190.0, 300.0, 500.0, 800.0, 1200.0, 2000.0}, "%.0f"); tool.radius = std::max(10.0, tool.radius); ImGui::DragScalar(STR_C("Speed (km/h)"), ImGuiDataType_Double, &tool.style.velocity, 1.0f, nullptr, nullptr, "%.0f"); - item_tooltip(m_norms_free ? "Speed limit of the new paths; the speed of the track joined comes first" - : "Speed limit of the new paths, and the design speed of the transition curves and of the cant; the speed of the track joined comes first, and none higher than the radius allows"); - if (false == m_norms_free) - value_chips("speeds", tool.style.velocity, {40.0, 60.0, 80.0, 100.0, 120.0, 160.0}, "%.0f"); + item_tooltip("Speed limit of the new paths, and the design speed of the transition curves and of the cant; the speed of the track joined comes first, and none higher than the radius allows"); + value_chips("speeds", tool.style.velocity, {40.0, 60.0, 80.0, 100.0, 120.0, 160.0}, "%.0f"); tool.style.velocity = std::clamp(tool.style.velocity, 0.0, 400.0); ImGui::PopItemWidth(); ImGui::Checkbox(STR_C("This speed also on from a track with its own"), &tool.own_speed); - item_tooltip(m_norms_free ? "Off: a track laid on from another one, or joined to it, takes the speed of that track.\nOn: the new tracks get the speed above" - : "Off: a track laid on from another one, or joined to it, is designed for the speed of that track and takes it.\nOn: it's designed for the speed above and the new tracks get it.\nWhile laying: Ctrl+Shift+wheel"); - if (auto const [from, to]{laying_ends()}; false == m_norms_free && (from != nullptr || to != nullptr)) + item_tooltip("Off: a track laid on from another one, or joined to it, is designed for the speed of that track and takes it.\nOn: it's designed for the speed above and the new tracks get it.\nWhile laying: Ctrl+Shift+wheel"); + if (auto const [from, to]{laying_ends()}; from != nullptr || to != nullptr) ImGui::TextDisabled("%s", design_speed_of(from, to).c_str()); ImGui::TextDisabled("%s", STR_C("Height of the track on the ground")); if (int heights{static_cast(EditorSettings.heights())}; diff --git a/application/editormodenmt.cpp b/application/editormodenmt.cpp index 59e394b8..05995e0e 100644 --- a/application/editormodenmt.cpp +++ b/application/editormodenmt.cpp @@ -1551,7 +1551,7 @@ void editor_mode::nmt_place_scenery(glm::dvec2 const &Point) void editor_mode::nmt_offer() { auto &state{m_nmt_state}; - if (state.offered || m_norms_prompt || false == m_lay.active || false == EditorSettings.terrain_offer()) + if (state.offered || false == m_lay.active || false == EditorSettings.terrain_offer()) return; state.offered = true; if (m_streamer.resident() > 0 || std::any_of(simulation::Paths.sequence().begin(), simulation::Paths.sequence().end(), [](TTrack const *Track) { return Track != nullptr && rail(*Track); })) diff --git a/application/editormoderoute.cpp b/application/editormoderoute.cpp index 8508b939..147a81e4 100644 --- a/application/editormoderoute.cpp +++ b/application/editormoderoute.cpp @@ -1345,8 +1345,6 @@ void editor_mode::render_route_gizmo() void editor_mode::render_route_ui() { auto &route{m_route}; - render_norms_choice(); - ImGui::Separator(); if (false == route.error.empty()) ImGui::TextColored(ImVec4(1.0f, 0.35f, 0.3f, 1.0f), "%s", route.error.c_str()); if (route.chain.tracks.empty()) @@ -1805,7 +1803,6 @@ bool editor_mode::render_route_vertex(int const Index) vertex.transition_in = std::max(0.0, vertex.transition_in); vertex.transition_out = std::max(0.0, vertex.transition_out); vertex.cant = std::max(0.0, vertex.cant); - if (false == m_norms_free) { if (ImGui::SmallButton(STR_C("Apply recommended for V"))) { diff --git a/application/editormodeselftest.cpp b/application/editormodeselftest.cpp index 629c4b19..041d6349 100644 --- a/application/editormodeselftest.cpp +++ b/application/editormodeselftest.cpp @@ -182,8 +182,6 @@ void editor_mode::selftest_step() if (false == line.empty() && line.front() != '#') test.lines.push_back(line); WriteLog("SELFTEST: " + std::to_string(test.lines.size()) + " steps from " + file); - // the scripts were written for the free laying, "norms plk" takes the norms - set_norms_free(true); } ++editor_selftest::frames(); // how long each frame took, for the longest one perf tells diff --git a/application/editormodeselftestjoin.cpp b/application/editormodeselftestjoin.cpp index 652f62a2..37b478ad 100644 --- a/application/editormodeselftestjoin.cpp +++ b/application/editormodeselftestjoin.cpp @@ -61,6 +61,7 @@ editor_mode::selftest_result editor_mode::selftest_join(std::string const &comma double height{0.0}; if (command == "join") { + // the transitions word left from the free laying: they follow the norms words >> radius >> variant >> transitions; // of the ends, for sceneries far above zero if (words >> height) @@ -86,7 +87,6 @@ editor_mode::selftest_result editor_mode::selftest_join(std::string const &comma } m_join_radius = radius; m_join_variant = variant; - m_lay.transitions = transitions != 0; pieces = join_pieces(tool.track, from.point, tool.point, tool.direction, to, length, error); } else @@ -168,10 +168,8 @@ editor_mode::selftest_result editor_mode::selftest_join(std::string const &comma } if (command == "norms") { - std::string which; - words >> which; - set_norms_free(which != "plk"); - WriteLog(std::string{"SELFTEST norms: "} + (m_norms_free ? "free" : "plk")); + // the tracks are laid to the norms only + WriteLog("SELFTEST norms: plk"); return selftest_result::handled; } if (command == "layspeed") diff --git a/application/editormodestraights.cpp b/application/editormodestraights.cpp index e5f23c66..312b677b 100644 --- a/application/editormodestraights.cpp +++ b/application/editormodestraights.cpp @@ -442,8 +442,7 @@ void editor_mode::render_straight_ui() ImGui::TextDisabled("%s", STR_C("Transition curves")); int transitions{state.auto_transitions ? 0 : 1}; if (segmented("straighttransitions", transitions, - {m_norms_free ? segment_option{0, STR_C("None"), "Plain arcs: the free design has no transition curves, the PKP PLK norms work them out from the speed of the line"} - : segment_option{0, STR_C("From the line speed"), "Lengths of the transition curves from the speed of the paths and the limits of the curve design"}, + {{0, STR_C("From the line speed"), "Lengths of the transition curves from the speed of the paths and the limits of the curve design"}, {1, STR_C("Given length"), "The same length of the transition curves at every curve"}})) state.auto_transitions = transitions == 0; if (false == state.auto_transitions) diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index 95379a2d..f07f5602 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -493,11 +493,6 @@ void editor_mode::show_track_tab(track_tab const Wanted) m_switch.armed = -1; m_signal.armed = false; m_track_tab = Tab; - if ((Tab == track_tab::lay || Tab == track_tab::straights || Tab == track_tab::route) && false == m_norms_asked && EditorSettings.norms() == editorSettings::track_norms::ask && std::getenv("EU07_EDITOR_SELFTEST") == nullptr) - { - m_norms_asked = true; - m_norms_prompt = true; - } auto *track{selected_track()}; switch (Tab) { @@ -1854,8 +1849,7 @@ std::string editor_mode::track_readout() const auto text{radius > 0.0 ? format("L %.2f m R %.0f m", length, radius) + speed_of(radius, laying_norms()) : format("L %.2f m %s", length, STR_C("straight"))}; if (auto const eased{eased_of(m_eased_last)}; false == eased.empty()) text += "\n" + eased; - if (false == m_norms_free) - text += "\n" + design_speed_of(m_extend.track, snapped ? target.track : nullptr); + text += "\n" + design_speed_of(m_extend.track, snapped ? target.track : nullptr); if (auto const vertical{vertical_of(pieces)}; false == vertical.empty()) text += "\n" + vertical; if (snapped) @@ -1890,7 +1884,6 @@ std::string editor_mode::track_readout() const text = format("L %.1f m %s", lay.preview_length, STR_C("straight")); if (auto const eased{eased_of(m_eased_last)}; false == eased.empty()) text += "\n" + eased; - if (false == m_norms_free) { auto const [from, to]{laying_ends()}; text += "\n" + design_speed_of(from, to); @@ -2009,7 +2002,7 @@ std::string editor_mode::track_shaping(bool const Joined) const auto text{std::string{STR_C(names[static_cast(m_track_layout)])}}; if (m_track_layout == track_layout::arc_straight || m_track_layout == track_layout::straight_arc) text += format(" R %.0f m", m_lay.radius); - return text + "\n" + STR("Ctrl+wheel: radius, Shift+wheel: arc / straight") + (m_norms_free ? std::string{} : STR(", Ctrl+Shift+wheel: speed")); + return text + "\n" + STR("Ctrl+wheel: radius, Shift+wheel: arc / straight") + STR(", Ctrl+Shift+wheel: speed"); } auto const &join{m_join_last}; char const *const kinds[]{"", "straight", "arc", "curve", "reverse curve", "free curve"}; @@ -2024,7 +2017,7 @@ std::string editor_mode::track_shaping(bool const Joined) const text += format(" V %.0f km/h", join.speed); if (join.variants > 1) text += format(" %d/%d", (m_join_variant % join.variants + join.variants) % join.variants + 1, join.variants); - return text + "\n" + STR("Ctrl+wheel: radius, Shift+wheel: another shape") + (m_norms_free ? std::string{} : STR(", Ctrl+Shift+wheel: speed")); + return text + "\n" + STR("Ctrl+wheel: radius, Shift+wheel: another shape") + STR(", Ctrl+Shift+wheel: speed"); } void editor_mode::draw_empty_scenery_hint() diff --git a/editor/editorSettings.cpp b/editor/editorSettings.cpp index fab20dcb..69244625 100644 --- a/editor/editorSettings.cpp +++ b/editor/editorSettings.cpp @@ -114,8 +114,18 @@ bool editorSettings::load() m_top_tracks = std::clamp(std::atoi(value.c_str()), 0, 2); else if (key == "top_rails") m_top_rails = static_cast(std::strtoul(value.c_str(), nullptr, 16)) | 0xff000000u; - else if (key == "track_norms") - m_norms = value == "free" ? track_norms::free_laying : value == "plk" ? track_norms::plk : track_norms::ask; + else if (key == "corner_radii") + { + // low;high + double low{0.0}, high{0.0}; + if (auto const separator{value.find(';')}; separator != std::string::npos) + { + parse(value.substr(0, separator), low); + parse(value.substr(separator + 1), high); + if (low >= 10.0 && high >= low) + corners(low, high); + } + } // under a key of its own since the laying goes from point to point unless told otherwise: the fitted heights chosen // before, when they were the default, are left behind else if (key == "laying_heights") @@ -168,7 +178,7 @@ bool editorSettings::save() stream << "track_tools_all " << (m_track_tools_more ? 1 : 0) << "\n"; stream << "top_tracks " << m_top_tracks << "\n"; stream << "top_rails " << std::hex << (m_top_rails & 0xffffffu) << std::dec << "\n"; - stream << "track_norms " << (m_norms == track_norms::free_laying ? "free" : m_norms == track_norms::plk ? "plk" : "ask") << "\n"; + stream << "corner_radii " << m_corner_low << ";" << m_corner_high << "\n"; stream << "laying_heights " << (m_heights == lay_heights::points ? "points" : m_heights == lay_heights::level ? "level" : "fitted") << "\n"; stream << std::fixed << std::setprecision(3); for (auto const &origin : m_orthophoto_origins) diff --git a/editor/editorSettings.hpp b/editor/editorSettings.hpp index b2572ca9..f98d965a 100644 --- a/editor/editorSettings.hpp +++ b/editor/editorSettings.hpp @@ -67,15 +67,14 @@ public: void top_tracks(int const Tracks) { m_top_tracks = Tracks; } std::uint32_t top_rails() const { return m_top_rails; } void top_rails(std::uint32_t const Colour) { m_top_rails = Colour; } - // how the new tracks are laid: asked as the laying starts, or the choice kept - enum class track_norms + // the radii the laying from point to point eases the bends of the straights with, at the peak of the two transition curves + double corner_low() const { return m_corner_low; } + double corner_high() const { return m_corner_high; } + void corners(double const Low, double const High) { - ask, - free_laying, - plk - }; - track_norms norms() const { return m_norms; } - void norms(track_norms Norms) { m_norms = Norms; } + m_corner_low = Low; + m_corner_high = High; + } // the heights of the tracks laid on the ground: fitted to it as the tracks go onto the terrain, the points clicked on it with // even grades between them, level enum class lay_heights @@ -101,7 +100,8 @@ private: bool m_track_tools_more{false}; int m_top_tracks{0}; // the railway in the top view: whole, without the ballast, the rails alone std::uint32_t m_top_rails{0xffff6e28}; // colour of the rails alone, as ImGui keeps it: ABGR - track_norms m_norms{track_norms::ask}; + double m_corner_low{3000.0}; + double m_corner_high{6000.0}; lay_heights m_heights{lay_heights::points}; };