diff --git a/application/editormode.cpp b/application/editormode.cpp index 9cd2df06..dccc7b20 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -1466,13 +1466,13 @@ bool editor_mode::update() draw_track_spread(); draw_build_overlay(); draw_track_intent(); - speed_step(); + m_speed.update(); joints_step(); draw_track_hints(); draw_empty_scenery_hint(); draw_profile_overlay(); draw_infra_overlay(); - draw_speed_overlay(); + m_speed.draw_overlay(); draw_joints_overlay(); } else diff --git a/application/editormode.h b/application/editormode.h index 7b0b0ade..2651ab36 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/. #include "input/editorkeyboardinput.h" #include "vehicle/Camera.h" #include "application/editormodegauge.h" +#include "application/editormodespeed.h" #include "application/editortool.h" #include "scene/sceneeditor.h" #include "scene/scenenode.h" @@ -745,7 +746,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri void render_track_gizmo(); void commit_track_drag(bool const Force); void cancel_track_tools(); - void push_track_snapshot(std::vector> States, std::vector Created = {}, std::vector Removed = {}); + void push_track_snapshot(std::vector> States, std::vector Created = {}, std::vector Removed = {}) override; + void set_current_node(scene::basic_node *Node) override; + alignment::limits const &route_norms() const override; // false, with the reason, when one of the paths can't be changed, its file not taking the changes back static bool tracks_editable(std::vector const &Tracks, std::string &Reason); void trim_history(); @@ -857,8 +860,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri std::string m_track_events_missing; void render_path_events(TTrack &Track); std::string m_track_mode_notice; - gauge_tool m_gauge{*this}; - std::vector m_tools{&m_gauge}; struct route_design { TTrack *from{nullptr}; @@ -1619,7 +1620,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri void track_context_release(); void render_track_context(); void split_track_at(TTrack &Track, glm::dvec3 const &Point); - void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point); + void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point) override; // the camera flies over Duration seconds to the place Distance back from the target along Look, looking along it void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) override; // paths found by their names @@ -2458,30 +2459,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri void infra_attach(EditorSnapshot &Snapshot); void render_infra_body(); - // speed limits of the paths checked against what their geometry allows - struct speed_state - { - bool open{false}; - int scope{0}; // 0: the line through the selected path, 1: the whole scenery - speed_check::options options; - std::vector> queue; - std::size_t next{0}; - std::vector results; - bool show_all{false}; - int limits{0}; // 0: all the paths, 1: only those with a speed limit set, 2: only those without - int selected{-1}; - std::size_t history{0}; // size of the undo history at the check - std::string status; - }; - speed_state m_speed; - void render_speed_body(); - void speed_start(); - void speed_step(); - void speed_focus(int const Index); - // with Branches the limits of the switch branches count too, otherwise they're only warnings - void speed_apply(std::vector const &Indices, bool const Branches); - std::vector speed_listed() const; - void draw_speed_overlay() const; + gauge_tool m_gauge{*this}; + speed_tool m_speed{*this}; + std::vector m_tools{&m_gauge, &m_speed}; // joints of the paths: ends which almost meet, steps, kinks, jumps of the cant and of the grade struct joints_state diff --git a/application/editormodespeed.cpp b/application/editormodespeed.cpp index 5eb8ea44..583c489f 100644 --- a/application/editormodespeed.cpp +++ b/application/editormodespeed.cpp @@ -8,8 +8,7 @@ http://mozilla.org/MPL/2.0/. */ #include "stdafx.h" -#include "application/editormode.h" -#include "application/editoruilayer.h" +#include "application/editormodespeed.h" #include "application/editorprojection.h" #include "application/editormodeshared.h" #include "editor/editorFormat.hpp" @@ -44,7 +43,7 @@ std::string speed_text(double const Speed) } // namespace -void editor_mode::speed_start() +void speed_tool::speed_start() { auto &state{m_speed}; state.queue.clear(); @@ -52,14 +51,14 @@ void editor_mode::speed_start() state.results.clear(); state.selected = -1; state.status.clear(); - state.options.norms = m_route.design.norms; + state.options.norms = m_services.route_norms(); auto const add = [&](TTrack *Track) { for (int i = 0; i < static_cast(Track->m_paths.size()); ++i) state.queue.emplace_back(Track, i); }; if (state.scope == 0) { - auto *track{selected_track()}; + auto *track{m_services.selected_track()}; if (track == nullptr || false == rail(*track)) { state.status = STR_C("Select a track first"); @@ -88,10 +87,10 @@ void editor_mode::speed_start() if (track != nullptr && rail(*track)) add(track); } - state.history = m_history.size(); + state.history = m_services.history_size(); } -void editor_mode::speed_step() +void speed_tool::update() { auto &state{m_speed}; if (state.next >= state.queue.size()) @@ -122,7 +121,7 @@ void editor_mode::speed_step() WriteLog("Editor: speed check - " + state.status, logtype::generic); } -std::vector editor_mode::speed_listed() const +std::vector speed_tool::speed_listed() const { std::vector listed; for (int i = 0; i < static_cast(m_speed.results.size()); ++i) @@ -136,7 +135,7 @@ std::vector editor_mode::speed_listed() const return listed; } -void editor_mode::speed_focus(int const Index) +void speed_tool::speed_focus(int const Index) { auto &state{m_speed}; if (Index < 0 || Index >= static_cast(state.results.size())) @@ -146,12 +145,11 @@ void editor_mode::speed_focus(int const Index) auto const &paths{simulation::Paths.sequence()}; if (std::find(paths.begin(), paths.end(), verdict.track) == paths.end() || verdict.track->m_editorremoved) return; - m_node = verdict.track; - ui()->set_node(m_node); - focus_track(*verdict.track, verdict.path, verdict.position); + m_services.set_current_node(verdict.track); + m_services.focus_track(*verdict.track, verdict.path, verdict.position); } -void editor_mode::speed_apply(std::vector const &Indices, bool const Branches) +void speed_tool::speed_apply(std::vector const &Indices, bool const Branches) { auto &state{m_speed}; struct change @@ -191,7 +189,7 @@ void editor_mode::speed_apply(std::vector const &Indices, bool const Branch state.status = STR_C("Nothing changed") + skipped; return; } - push_track_snapshot(std::move(states)); + m_services.push_track_snapshot(std::move(states)); for (auto const &entry : changes) { auto const velocity{entry.track->eType == tt_Switch ? speed_check::switch_velocity(entry.limits[0], entry.limits[1]) : entry.limits[0]}; @@ -200,12 +198,12 @@ void editor_mode::speed_apply(std::vector const &Indices, bool const Branch } for (auto &verdict : state.results) verdict.set = speed_check::path_velocity(*verdict.track, verdict.path); - state.history = m_history.size(); + state.history = m_services.history_size(); state.status = format(STR_C("Speed limits of %zu paths lowered to the safe ones, Ctrl+Z brings them back"), changes.size()) + skipped; WriteLog("Editor: speed check - " + state.status, logtype::generic); } -void editor_mode::render_speed_body() +void speed_tool::render_options() { auto &state{m_speed}; ImGui::PushTextWrapPos(0.0f); @@ -264,7 +262,7 @@ void editor_mode::render_speed_body() ImGui::TextWrapped("%s", state.status.c_str()); if (state.results.empty()) return; - if (state.history != m_history.size()) + if (state.history != m_services.history_size()) ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.3f, 1.0f), STR_C("The scenery changed since the check")); auto const *const within{STR_C("Within their limits too")}; auto const checkbox{ImGui::GetFrameHeight() + ImGui::GetStyle().ItemInnerSpacing.x + ImGui::CalcTextSize(within).x}; @@ -357,7 +355,7 @@ void editor_mode::render_speed_body() } } -void editor_mode::draw_speed_overlay() const +void speed_tool::draw_overlay() const { auto const &state{m_speed}; if (false == state.open || state.results.empty()) @@ -380,3 +378,30 @@ void editor_mode::draw_speed_overlay() const drawlist->AddText(ImVec2(screen.x + 14.0f, screen.y - 7.0f), colour, text.c_str()); } } + +void speed_tool::check_line() +{ + m_speed.scope = 0; + speed_start(); +} + +editor_selftest_result speed_tool::selftest(std::string const &Command, std::istringstream &Words) +{ + if (Command == "speedcheck") + { + int scope{0}; + Words >> scope; + m_speed.scope = scope; + speed_start(); + while (m_speed.next < m_speed.queue.size()) + update(); + WriteLog("SELFTEST speedcheck: " + m_speed.status); + for (auto const index : speed_listed()) + { + auto const &verdict{m_speed.results[index]}; + WriteLog(format("SELFTEST speedcheck %s path %d: set %.0f safe %.0f", verdict.track->name().c_str(), verdict.path, verdict.set, verdict.safe)); + } + return editor_selftest_result::handled; + } + return editor_selftest_result::unhandled; +} diff --git a/application/editormodespeed.h b/application/editormodespeed.h new file mode 100644 index 00000000..a477f59a --- /dev/null +++ b/application/editormodespeed.h @@ -0,0 +1,53 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "application/editortool.h" +#include "editor/editorSpeed.hpp" + +#include +#include +#include + +class speed_tool final : public editor_tool +{ + public: + explicit speed_tool(editor_services &Services) : m_services{Services} {} + void update() override; + void draw_overlay() const override; + void render_options() override; + editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) override; + void set_open(bool const Open) { m_speed.open = Open; } + void check_line(); + + private: + editor_services &m_services; + // speed limits of the paths checked against what their geometry allows + struct speed_state + { + bool open{false}; + int scope{0}; // 0: the line through the selected path, 1: the whole scenery + speed_check::options options; + std::vector> queue; + std::size_t next{0}; + std::vector results; + bool show_all{false}; + int limits{0}; // 0: all the paths, 1: only those with a speed limit set, 2: only those without + int selected{-1}; + std::size_t history{0}; // size of the undo history at the check + std::string status; + }; + speed_state m_speed; + void speed_start(); + void speed_focus(int const Index); + // with Branches the limits of the switch branches count too, otherwise they're only warnings + void speed_apply(std::vector const &Indices, bool const Branches); + std::vector speed_listed() const; +}; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index b84d6bf8..f00f060f 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -67,6 +67,17 @@ glm::dvec3 editor_mode::camera_position() const return Camera.Pos; } +void editor_mode::set_current_node(scene::basic_node *Node) +{ + m_node = Node; + ui()->set_node(m_node); +} + +alignment::limits const &editor_mode::route_norms() const +{ + return m_route.design.norms; +} + void editor_mode::select_track(scene::basic_node *Node) { auto *track = dynamic_cast(Node); @@ -514,7 +525,7 @@ void editor_mode::render_track_inspector() { auto const &io{ImGui::GetIO()}; m_profile.open = m_track_window_open && m_track_tab == track_tab::profile; - m_speed.open = m_track_window_open && m_track_tab == track_tab::speed; + m_speed.set_open(m_track_window_open && m_track_tab == track_tab::speed); m_infra.open = m_track_window_open && m_track_tab == track_tab::infra; m_joints.open = m_track_window_open && m_track_tab == track_tab::joints; if (false == m_track_window_open || m_track_tab != track_tab::lineside) @@ -547,7 +558,7 @@ void editor_mode::render_track_inspector() { switch (m_track_tab) { - case track_tab::speed: render_speed_body(); break; + case track_tab::speed: m_speed.render_options(); break; case track_tab::joints: render_joints_body(); break; default: render_infra_body(); break; } diff --git a/application/editormodetrackux.cpp b/application/editormodetrackux.cpp index 9518c5ca..9c551577 100644 --- a/application/editormodetrackux.cpp +++ b/application/editormodetrackux.cpp @@ -814,9 +814,8 @@ void editor_mode::render_track_context() } if (ImGui::MenuItem(STR_C("Speed check of the line"), "V")) { - m_speed.scope = 0; show_track_tab(track_tab::speed); - speed_start(); + m_speed.check_line(); } ImGui::Separator(); if (ImGui::MenuItem(track_selected(track) ? STR_C("Take out of the selection") : STR_C("Add to the selection"), STR_C("Shift+LMB"))) diff --git a/application/editortool.h b/application/editortool.h index 1ddfc50f..2e3eb275 100644 --- a/application/editortool.h +++ b/application/editortool.h @@ -12,9 +12,13 @@ http://mozilla.org/MPL/2.0/. #include #include #include +#include +#include #include +#include "editor/editorTrack.hpp" + class TTrack; namespace scene { @@ -36,6 +40,10 @@ class editor_services virtual std::size_t history_size() const = 0; virtual glm::dvec3 camera_position() const = 0; virtual void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) = 0; + virtual void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point) = 0; + virtual void set_current_node(scene::basic_node *Node) = 0; + virtual alignment::limits const &route_norms() const = 0; + virtual void push_track_snapshot(std::vector> States, std::vector Created = {}, std::vector Removed = {}) = 0; protected: ~editor_services() = default; @@ -46,6 +54,8 @@ class editor_tool public: virtual ~editor_tool() = default; virtual void update() {} + virtual void draw_overlay() const {} + virtual void render_options() {} virtual void render_windows() {} virtual void forget(scene::basic_node const *Node) {} virtual editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) { return editor_selftest_result::unhandled; }