diff --git a/application/editormode.cpp b/application/editormode.cpp index dccc7b20..19559df6 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -1467,13 +1467,13 @@ bool editor_mode::update() draw_build_overlay(); draw_track_intent(); m_speed.update(); - joints_step(); + m_joints.update(); draw_track_hints(); draw_empty_scenery_hint(); draw_profile_overlay(); draw_infra_overlay(); m_speed.draw_overlay(); - draw_joints_overlay(); + m_joints.draw_overlay(); } else { diff --git a/application/editormode.h b/application/editormode.h index 2651ab36..3d5c3140 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/editormodejoints.h" #include "application/editormodespeed.h" #include "application/editortool.h" #include "scene/sceneeditor.h" @@ -65,19 +66,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri { public: - // joint of the paths found wrong by the joints check - struct joint_issue - { - enum class kind { gap, step, kink, cant, grade, model, open }; - kind type{kind::gap}; - TTrack *track{nullptr}; - editor_track::point_ref point; - TTrack *other{nullptr}; - editor_track::point_ref theirs; - glm::dvec3 position{0.0}; - double value{0.0}; // m, deg, mm, per mille; m of the track over the terrain model - bool fixed{false}; - }; // constructors editor_mode(); ~editor_mode() override; @@ -318,16 +306,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri bool add_chunk_from_ground(heightmap::chunk_key const &Key, float const Spacing, std::uint16_t const Layer = 0); // the terrain from the digital terrain model of GUGiK (editormodenmt.cpp) - struct nmt_place - { - glm::dvec3 position{0.0}; // on the axis of the path - double formation{0.0}; // the height of the formation under it, the foot of the ballast - double crown{0.0}; // the height of the top of the ballast under the rails: what the terrain model measures on a track - double half_width{3.0}; // from the axis to the foot of the ballast - TTrack *track{nullptr}; - int path{0}; - bool shapes{true}; // not a bridge nor a tunnel - }; + using nmt_place = ::nmt_place; struct nmt_state { double offset{0.0}; // added to the heights of the model, so they meet the tracks of the scenery @@ -383,8 +362,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri }; editor_nmt m_nmt; nmt_state m_nmt_state; - std::vector nmt_track_places(double const Step) const; - void nmt_locate(); + std::vector nmt_track_places(double const Step) const override; + void nmt_locate() override; bool nmt_choice_card(int const Index, char const *Title, char const *Text, float const Width, float const TextHeight, bool const Chosen) const; void nmt_fit(); void nmt_finish_fit(); @@ -749,6 +728,10 @@ class editor_mode : public application_mode, private editor_track::observer, pri 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; + void clear_track_point() override; + editor_nmt &terrain_model() override; + double terrain_model_offset() const override; + bool terrain_model_fitted() 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(); @@ -2461,49 +2444,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri gauge_tool m_gauge{*this}; speed_tool m_speed{*this}; - std::vector m_tools{&m_gauge, &m_speed}; + joints_tool m_joints{*this}; + std::vector m_tools{&m_gauge, &m_speed, &m_joints}; - // joints of the paths: ends which almost meet, steps, kinks, jumps of the cant and of the grade - struct joints_state - { - bool open{false}; - int scope{0}; // 0: around the camera, 1: the whole scenery - double reach{2000.0}; - double gap{1.0}; // m, free ends closer than this to another end - double step{0.005}; // m - double angle{0.2}; // deg - double cant{5.0}; // mm - double grade{10.0}; // per mille - double model{0.5}; // m, the track over or under the terrain model (NMT) - bool free_ends{false}; - bool model_check{true}; - std::vector queue; - std::size_t next{0}; - // the places of the tracks compared with the terrain model, in runs of one path each, once the model under them is in - std::vector places; - std::vector> runs; - std::size_t run_next{0}; - bool model_waiting{false}; - bool model_asked{false}; - double model_polled{0.0}; - bool model_unplaced{false}; - std::vector issues; - int filter{-1}; - int selected{-1}; - std::size_t history{0}; - std::string status; - }; - joints_state m_joints; - void joints_start(); - void joints_step(); - void joints_check(TTrack &Track); - // the paths lying off the terrain model by more than the threshold. returns: false while the model under them is coming - bool joints_model(); - void joints_focus(int const Index); - bool joint_fix(joint_issue &Issue, std::vector> &States, std::vector &Changed); - void joints_fix(std::vector const &Indices); - void render_joints_body(); - void draw_joints_overlay() const; void infra_rebase(); void render_infra_search(); void render_infra_candidates(); diff --git a/application/editormodejoints.cpp b/application/editormodejoints.cpp index 856623cc..5177de0e 100644 --- a/application/editormodejoints.cpp +++ b/application/editormodejoints.cpp @@ -8,9 +8,9 @@ http://mozilla.org/MPL/2.0/. */ #include "stdafx.h" -#include "application/editormode.h" +#include "application/editormodejoints.h" +#include "editor/editorNmt.hpp" #include "application/editormodeshared.h" -#include "application/editoruilayer.h" #include "application/editorprojection.h" #include "editor/editorFormat.hpp" #include "editor/editorGeometry.hpp" @@ -46,7 +46,7 @@ std::size_t const kModelRun{200}; // places of a path whose model is asked for a double const kModelPoll{0.25}; // s between the looks whether the model is in double const kUnfitted{30.0}; // m; a scenery whose tracks lie this far from the model as a whole isn't fitted to it -using kind = editor_mode::joint_issue::kind; +using kind = joints_tool::joint_issue::kind; bool rail(TTrack const &Track) { @@ -109,7 +109,7 @@ char const *kind_name(kind const Kind) } } -std::string value_text(editor_mode::joint_issue const &Issue) +std::string value_text(joints_tool::joint_issue const &Issue) { switch (Issue.type) { @@ -146,7 +146,7 @@ std::string name_of(TTrack const *Track) } // namespace -void editor_mode::joints_start() +void joints_tool::joints_start() { auto &state{m_joints}; state.queue.clear(); @@ -164,7 +164,7 @@ void editor_mode::joints_start() continue; state.queue.push_back(track); } - state.history = m_history.size(); + state.history = m_services.history_size(); state.places.clear(); state.runs.clear(); state.run_next = 0; @@ -174,14 +174,14 @@ void editor_mode::joints_start() state.model_unplaced = false; if (false == state.model_check || state.queue.empty()) return; - nmt_locate(); - if (false == m_nmt.placed()) + m_services.nmt_locate(); + if (false == m_services.terrain_model().placed()) { state.model_unplaced = true; return; } std::set const queued(state.queue.begin(), state.queue.end()); - for (auto const &place : nmt_track_places(kModelStep)) + for (auto const &place : m_services.nmt_track_places(kModelStep)) if (place.shapes && queued.count(place.track) > 0) { if (state.places.empty() || state.places.back().track != place.track || state.places.back().path != place.path || state.places.size() - state.runs.back().first >= kModelRun) @@ -192,7 +192,7 @@ void editor_mode::joints_start() state.model_waiting = false == state.places.empty(); } -bool editor_mode::joints_model() +bool joints_tool::joints_model() { auto &state{m_joints}; auto const now{ImGui::GetTime()}; @@ -216,27 +216,27 @@ bool editor_mode::joints_model() for (auto const &run : state.runs) { box(run, low, high); - m_nmt.request(low, high); + m_services.terrain_model().request(low, high); } state.model_asked = true; } while (state.run_next < state.runs.size()) { box(state.runs[state.run_next], low, high); - if (false == m_nmt.request(low, high)) + if (false == m_services.terrain_model().request(low, high)) return false; ++state.run_next; } std::vector differences(state.places.size(), std::numeric_limits::quiet_NaN()); std::vector known; for (std::size_t i = 0; i < state.places.size(); ++i) - if (double height; m_nmt.height(state.places[i].position.x, state.places[i].position.z, height)) + if (double height; m_services.terrain_model().height(state.places[i].position.x, state.places[i].position.z, height)) { - differences[i] = state.places[i].crown - (height + m_nmt_state.offset); + differences[i] = state.places[i].crown - (height + m_services.terrain_model_offset()); known.push_back(differences[i]); } auto shift{0.0}; - if (false == m_nmt_state.fitted && false == known.empty()) + if (false == m_services.terrain_model_fitted() && false == known.empty()) { std::nth_element(known.begin(), known.begin() + known.size() / 2, known.end()); if (std::abs(known[known.size() / 2]) > kUnfitted) @@ -275,7 +275,7 @@ bool editor_mode::joints_model() return true; } -void editor_mode::joints_check(TTrack &Track) +void joints_tool::joints_check(TTrack &Track) { auto &state{m_joints}; auto const once = [&](end_key const &A, end_key const &B) { return reported.insert(A < B ? std::make_pair(A, B) : std::make_pair(B, A)).second; }; @@ -366,7 +366,7 @@ void editor_mode::joints_check(TTrack &Track) } } -void editor_mode::joints_step() +void joints_tool::update() { auto &state{m_joints}; if (state.next >= state.queue.size() && false == state.model_waiting) @@ -401,7 +401,7 @@ void editor_mode::joints_step() WriteLog("Editor: joints check - " + state.status, logtype::generic); } -void editor_mode::joints_focus(int const Index) +void joints_tool::joints_focus(int const Index) { auto &state{m_joints}; if (Index < 0 || Index >= static_cast(state.issues.size())) @@ -411,13 +411,12 @@ void editor_mode::joints_focus(int const Index) auto const &paths{simulation::Paths.sequence()}; if (std::find(paths.begin(), paths.end(), issue.track) == paths.end() || issue.track->m_editorremoved) return; - m_node = issue.track; - m_track_point = {}; - ui()->set_node(m_node); - focus_track(*issue.track, issue.point.path, issue.position); + m_services.set_current_node(issue.track); + m_services.clear_track_point(); + m_services.focus_track(*issue.track, issue.point.path, issue.position); } -bool editor_mode::joint_fix(joint_issue &Issue, std::vector> &States, std::vector &Changed) +bool joints_tool::joint_fix(joint_issue &Issue, std::vector> &States, std::vector &Changed) { if (Issue.fixed || Issue.type == kind::open || Issue.type == kind::model || Issue.track == nullptr || Issue.other == nullptr || Issue.track->m_editorremoved || Issue.other->m_editorremoved) return false; @@ -481,7 +480,7 @@ bool editor_mode::joint_fix(joint_issue &Issue, std::vector const &Indices) +void joints_tool::joints_fix(std::vector const &Indices) { auto &state{m_joints}; std::vector> states; @@ -499,16 +498,16 @@ void editor_mode::joints_fix(std::vector const &Indices) state.status = STR_C("Nothing could be fixed: the paths are switches or in the files which can't be changed"); return; } - push_track_snapshot(std::move(states)); + m_services.push_track_snapshot(std::move(states)); editor_track::commit(changed); for (auto *track : changed) track->mark_dirty(); - state.history = m_history.size(); + state.history = m_services.history_size(); state.status = format(STR_C("%zu joints fixed, Ctrl+Z takes them back"), count); WriteLog("Editor: joints check - " + state.status, logtype::generic); } -void editor_mode::render_joints_body() +void joints_tool::render_options() { auto &state{m_joints}; ImGui::PushTextWrapPos(0.0f); @@ -581,7 +580,7 @@ void editor_mode::render_joints_body() ImGui::TextWrapped("%s", state.status.c_str()); if (state.issues.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), "%s", STR_C("The scenery changed since the check")); int filter{state.filter + 1}; ImGui::SetNextItemWidth(150.0f); @@ -649,7 +648,7 @@ void editor_mode::render_joints_body() } } -void editor_mode::draw_joints_overlay() const +void joints_tool::draw_overlay() const { auto const &state{m_joints}; if (false == state.open || state.issues.empty()) @@ -671,3 +670,63 @@ void editor_mode::draw_joints_overlay() const drawlist->AddText(ImVec2(screen.x + 13.0f, screen.y - 7.0f), colour, text.c_str()); } } + +editor_selftest_result joints_tool::selftest(std::string const &Command, std::istringstream &Words) +{ + if (Command == "jointsmodel") + { + // the whole scenery against the terrain model, as the check of the panel does it, waiting for the model + static bool started{false}; + if (false == started) + { + double threshold{0.5}; + Words >> threshold; + m_joints.scope = 1; + m_joints.model_check = true; + m_joints.model = threshold; + joints_start(); + started = true; + } + update(); + if (m_joints.next < m_joints.queue.size() || m_joints.model_waiting) + return editor_selftest_result::again; + started = false; + std::size_t count{0}; + for (auto const &issue : m_joints.issues) + if (issue.type == joint_issue::kind::model && count++ < 40) + WriteLog(format("SELFTEST jointsmodel: %+.2f m at %.1f %.1f, %s path %d", issue.value, issue.position.x, issue.position.z, issue.track != nullptr ? issue.track->name().c_str() : "-", issue.point.path)); + WriteLog("SELFTEST jointsmodel: " + m_joints.status); + return editor_selftest_result::handled; + } + if (Command == "joints") + { + std::vector points; + for (glm::dvec3 point{0.0}; Words >> point.x >> point.z;) + points.push_back(point); + auto const scope{m_joints.scope}; + auto const model{m_joints.model_check}; + m_joints.scope = 1; + m_joints.model_check = false; + joints_start(); + while (m_joints.next < m_joints.queue.size()) + update(); + m_joints.scope = scope; + m_joints.model_check = model; + char const *const kinds[]{"gap", "step", "kink", "cant jump", "grade break", "off the terrain model", "free end"}; + int around{0}; + for (auto const &issue : m_joints.issues) + { + if (false == points.empty() && issue.type == joint_issue::kind::open) + continue; + if (false == points.empty() && std::none_of(points.begin(), points.end(), [&](glm::dvec3 const &Point) { return geometry::plan_distance(Point, issue.position) < 5.0; })) + continue; + ++around; + auto const name = [](TTrack const *Track) { return Track == nullptr ? std::string{"-"} : Track->name() + (Track->eType == tt_Switch ? "(switch)" : ""); }; + auto const rise{issue.other != nullptr ? editor_track::point_position(*issue.other, issue.theirs).y - issue.position.y : 0.0}; + WriteLog(format("SELFTEST joints: %s %.3f at %.1f %.1f, %s / %s, rise %.3f", kinds[static_cast(issue.type)], issue.value, issue.position.x, issue.position.z, name(issue.track).c_str(), name(issue.other).c_str(), rise)); + } + WriteLog(format("SELFTEST joints: %d issues around the points, %zu in all", around, m_joints.issues.size())); + return editor_selftest_result::handled; + } + return editor_selftest_result::unhandled; +} diff --git a/application/editormodejoints.h b/application/editormodejoints.h new file mode 100644 index 00000000..34dc5cbe --- /dev/null +++ b/application/editormodejoints.h @@ -0,0 +1,82 @@ +/* +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 +#include +#include + +class joints_tool final : public editor_tool +{ + public: + // joint of the paths found wrong by the joints check + struct joint_issue + { + enum class kind { gap, step, kink, cant, grade, model, open }; + kind type{kind::gap}; + TTrack *track{nullptr}; + editor_track::point_ref point; + TTrack *other{nullptr}; + editor_track::point_ref theirs; + glm::dvec3 position{0.0}; + double value{0.0}; // m, deg, mm, per mille; m of the track over the terrain model + bool fixed{false}; + }; + explicit joints_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_joints.open = Open; } + double kink_angle() const { return m_joints.angle; } + + private: + editor_services &m_services; + // joints of the paths: ends which almost meet, steps, kinks, jumps of the cant and of the grade + struct joints_state + { + bool open{false}; + int scope{0}; // 0: around the camera, 1: the whole scenery + double reach{2000.0}; + double gap{1.0}; // m, free ends closer than this to another end + double step{0.005}; // m + double angle{0.2}; // deg + double cant{5.0}; // mm + double grade{10.0}; // per mille + double model{0.5}; // m, the track over or under the terrain model (NMT) + bool free_ends{false}; + bool model_check{true}; + std::vector queue; + std::size_t next{0}; + // the places of the tracks compared with the terrain model, in runs of one path each, once the model under them is in + std::vector places; + std::vector> runs; + std::size_t run_next{0}; + bool model_waiting{false}; + bool model_asked{false}; + double model_polled{0.0}; + bool model_unplaced{false}; + std::vector issues; + int filter{-1}; + int selected{-1}; + std::size_t history{0}; + std::string status; + }; + joints_state m_joints; + void joints_start(); + void joints_check(TTrack &Track); + // the paths lying off the terrain model by more than the threshold. returns: false while the model under them is coming + bool joints_model(); + void joints_focus(int const Index); + bool joint_fix(joint_issue &Issue, std::vector> &States, std::vector &Changed); + void joints_fix(std::vector const &Indices); +}; diff --git a/application/editormodelay.cpp b/application/editormodelay.cpp index d66b7608..f6cbb46b 100644 --- a/application/editormodelay.cpp +++ b/application/editormodelay.cpp @@ -470,7 +470,7 @@ std::vector editor_mode::join_pieces(TTrack const *From, editor_tr request.variant = m_join_variant; request.transitions = m_lay.transitions; request.speed = design_speed(From, End.track); - request.kink = m_joints.angle * 0.5; + request.kink = m_joints.kink_angle() * 0.5; request.shape = m_route.design.shape; request.norms = laying_norms(); auto result{alignment::join(request)}; diff --git a/application/editormodeselftest.cpp b/application/editormodeselftest.cpp index dc810c1d..731c0b11 100644 --- a/application/editormodeselftest.cpp +++ b/application/editormodeselftest.cpp @@ -188,8 +188,12 @@ void editor_mode::selftest_step() words >> test.wait; return; } - if (selftest_dispatch(command, words) == selftest_result::pause) + if (auto const result{selftest_dispatch(command, words)}; result == selftest_result::pause || result == selftest_result::again) + { + if (result == selftest_result::again) + --test.next; return; + } if (command == "quit") { if (false == test.quitting) diff --git a/application/editormodeselftestjoin.cpp b/application/editormodeselftestjoin.cpp index 17f1791d..f5ac36d8 100644 --- a/application/editormodeselftestjoin.cpp +++ b/application/editormodeselftestjoin.cpp @@ -236,64 +236,6 @@ editor_mode::selftest_result editor_mode::selftest_join(std::string const &comma WriteLog(format("SELFTEST layclicks %d paths, ballast foot over the ground up to %.3f m, under it up to %.3f m", paths, hanging, buried)); return selftest_result::handled; } - if (command == "jointsmodel") - { - // the whole scenery against the terrain model, as the check of the panel does it, waiting for the model - static bool started{false}; - if (false == started) - { - double threshold{0.5}; - words >> threshold; - m_joints.scope = 1; - m_joints.model_check = true; - m_joints.model = threshold; - joints_start(); - started = true; - } - joints_step(); - if (m_joints.next < m_joints.queue.size() || m_joints.model_waiting) - { - --m_selftest.next; - return selftest_result::pause; - } - started = false; - std::size_t count{0}; - for (auto const &issue : m_joints.issues) - if (issue.type == joint_issue::kind::model && count++ < 40) - WriteLog(format("SELFTEST jointsmodel: %+.2f m at %.1f %.1f, %s path %d", issue.value, issue.position.x, issue.position.z, issue.track != nullptr ? issue.track->name().c_str() : "-", issue.point.path)); - WriteLog("SELFTEST jointsmodel: " + m_joints.status); - return selftest_result::handled; - } - if (command == "joints") - { - std::vector points; - for (glm::dvec3 point{0.0}; words >> point.x >> point.z;) - points.push_back(point); - auto const scope{m_joints.scope}; - auto const model{m_joints.model_check}; - m_joints.scope = 1; - m_joints.model_check = false; - joints_start(); - while (m_joints.next < m_joints.queue.size()) - joints_step(); - m_joints.scope = scope; - m_joints.model_check = model; - char const *const kinds[]{"gap", "step", "kink", "cant jump", "grade break", "off the terrain model", "free end"}; - int around{0}; - for (auto const &issue : m_joints.issues) - { - if (false == points.empty() && issue.type == joint_issue::kind::open) - continue; - if (false == points.empty() && std::none_of(points.begin(), points.end(), [&](glm::dvec3 const &Point) { return geometry::plan_distance(Point, issue.position) < 5.0; })) - continue; - ++around; - auto const name = [](TTrack const *Track) { return Track == nullptr ? std::string{"-"} : Track->name() + (Track->eType == tt_Switch ? "(switch)" : ""); }; - auto const rise{issue.other != nullptr ? editor_track::point_position(*issue.other, issue.theirs).y - issue.position.y : 0.0}; - WriteLog(format("SELFTEST joints: %s %.3f at %.1f %.1f, %s / %s, rise %.3f", kinds[static_cast(issue.type)], issue.value, issue.position.x, issue.position.z, name(issue.track).c_str(), name(issue.other).c_str(), rise)); - } - WriteLog(format("SELFTEST joints: %d issues around the points, %zu in all", around, m_joints.issues.size())); - return selftest_result::handled; - } if (command == "gizmo") { std::string action; diff --git a/application/editormodeswitchplace.cpp b/application/editormodeswitchplace.cpp index 2275c361..1856afce 100644 --- a/application/editormodeswitchplace.cpp +++ b/application/editormodeswitchplace.cpp @@ -583,7 +583,7 @@ bool editor_mode::plan_switch_link(switch_link &Plan) const } if (shape.length > line.length - 0.02) return false; - auto const kink{glm::radians(m_joints.angle * 0.5)}; + auto const kink{glm::radians(m_joints.kink_angle() * 0.5)}; auto const plan = [&](double const Along) { Plan.along = Along; Plan.paths = place(Along); @@ -643,7 +643,7 @@ bool editor_mode::plan_branch_link(editor_track::branch_link &Link, std::string return false; auto const &diverging{tool.track->m_paths[1]}; auto const radius{editor_track::branch_radius(diverging)}; - Link = editor_track::link_branch(branch_start(diverging), radius, branch_target(target), glm::radians(m_joints.angle * 0.5), + Link = editor_track::link_branch(branch_start(diverging), radius, branch_target(target), glm::radians(m_joints.kink_angle() * 0.5), editor_track::reverse_insert(std::min(editor_track::diverging_speed(radius), design_speed(tool.track, target.track))), stretchable(target)); Reason = link_problem(target, Link); return Reason.empty(); diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index f00f060f..3aa605f1 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -78,6 +78,26 @@ alignment::limits const &editor_mode::route_norms() const return m_route.design.norms; } +void editor_mode::clear_track_point() +{ + m_track_point = {}; +} + +editor_nmt &editor_mode::terrain_model() +{ + return m_nmt; +} + +double editor_mode::terrain_model_offset() const +{ + return m_nmt_state.offset; +} + +bool editor_mode::terrain_model_fitted() const +{ + return m_nmt_state.fitted; +} + void editor_mode::select_track(scene::basic_node *Node) { auto *track = dynamic_cast(Node); @@ -527,7 +547,7 @@ void editor_mode::render_track_inspector() m_profile.open = m_track_window_open && m_track_tab == track_tab::profile; 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; + m_joints.set_open(m_track_window_open && m_track_tab == track_tab::joints); if (false == m_track_window_open || m_track_tab != track_tab::lineside) { m_sweep.open = false; @@ -559,7 +579,7 @@ void editor_mode::render_track_inspector() switch (m_track_tab) { case track_tab::speed: m_speed.render_options(); break; - case track_tab::joints: render_joints_body(); break; + case track_tab::joints: m_joints.render_options(); break; default: render_infra_body(); break; } } diff --git a/application/editortool.h b/application/editortool.h index 2e3eb275..2c746dc8 100644 --- a/application/editortool.h +++ b/application/editortool.h @@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/. #include "editor/editorTrack.hpp" class TTrack; +class editor_nmt; namespace scene { class basic_node; @@ -29,7 +30,19 @@ enum class editor_selftest_result { unhandled, handled, - pause + pause, + again +}; + +struct nmt_place +{ + glm::dvec3 position{0.0}; // on the axis of the path + double formation{0.0}; // the height of the formation under it, the foot of the ballast + double crown{0.0}; // the height of the top of the ballast under the rails: what the terrain model measures on a track + double half_width{3.0}; // from the axis to the foot of the ballast + TTrack *track{nullptr}; + int path{0}; + bool shapes{true}; // not a bridge nor a tunnel }; class editor_services @@ -43,6 +56,12 @@ class editor_services 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 clear_track_point() = 0; + virtual void nmt_locate() = 0; + virtual std::vector nmt_track_places(double const Step) const = 0; + virtual editor_nmt &terrain_model() = 0; + virtual double terrain_model_offset() const = 0; + virtual bool terrain_model_fitted() const = 0; virtual void push_track_snapshot(std::vector> States, std::vector Created = {}, std::vector Removed = {}) = 0; protected: