mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-26 17:04:53 +01:00
refactor(editor): the joints check is a tool of its own
The third tool out of editor_mode. It reaches the terrain model and the places of the tracks on it through the services, the place of a track for the terrain model is a type of its own now, and the laying and the switches ask the tool for the kink it allows. A self-test command can ask to be run again in the next frame, as the check against the terrain model does while the model comes in.
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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_place> nmt_track_places(double const Step) const;
|
||||
void nmt_locate();
|
||||
std::vector<nmt_place> 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<std::pair<TTrack *, editor_track::state>> States, std::vector<TTrack *> Created = {}, std::vector<TTrack *> 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<TTrack *> 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<editor_tool *> m_tools{&m_gauge, &m_speed};
|
||||
joints_tool m_joints{*this};
|
||||
std::vector<editor_tool *> 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<TTrack *> 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<nmt_place> places;
|
||||
std::vector<std::pair<std::size_t, std::size_t>> 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<joint_issue> 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<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &Changed);
|
||||
void joints_fix(std::vector<int> const &Indices);
|
||||
void render_joints_body();
|
||||
void draw_joints_overlay() const;
|
||||
void infra_rebase();
|
||||
void render_infra_search();
|
||||
void render_infra_candidates();
|
||||
|
||||
@@ -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<TTrack const *> 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<double> differences(state.places.size(), std::numeric_limits<double>::quiet_NaN());
|
||||
std::vector<double> 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<int>(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<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &Changed)
|
||||
bool joints_tool::joint_fix(joint_issue &Issue, std::vector<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &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<std::pair<TTrack *,
|
||||
return true;
|
||||
}
|
||||
|
||||
void editor_mode::joints_fix(std::vector<int> const &Indices)
|
||||
void joints_tool::joints_fix(std::vector<int> const &Indices)
|
||||
{
|
||||
auto &state{m_joints};
|
||||
std::vector<std::pair<TTrack *, editor_track::state>> states;
|
||||
@@ -499,16 +498,16 @@ void editor_mode::joints_fix(std::vector<int> 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<glm::dvec3> 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<int>(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;
|
||||
}
|
||||
|
||||
82
application/editormodejoints.h
Normal file
82
application/editormodejoints.h
Normal file
@@ -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 <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
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<TTrack *> 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<nmt_place> places;
|
||||
std::vector<std::pair<std::size_t, std::size_t>> 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<joint_issue> 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<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &Changed);
|
||||
void joints_fix(std::vector<int> const &Indices);
|
||||
};
|
||||
@@ -470,7 +470,7 @@ std::vector<segment_data> 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)};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<glm::dvec3> 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<int>(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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<TTrack *>(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_place> 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<std::pair<TTrack *, editor_track::state>> States, std::vector<TTrack *> Created = {}, std::vector<TTrack *> Removed = {}) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user