mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-26 17:04:53 +01:00
feat(editor): a measuring tape in the track mode, M: the distance, the difference of height, the grade and the azimuth between two clicks
M in any tab of the track mode turns the tape on: a click puts its start, the next one its end, at a free end, on the axis of the track under the cursor or else on the ground. The readout at the cursor gives the distance in plan and in space, the difference of height and the grade between them and the azimuth, while the second point follows the cursor and once it's put; a further click starts a new measure, M or Esc puts the tape away. Self-test command tape.
This commit is contained in:
@@ -1494,12 +1494,14 @@ bool editor_mode::update()
|
||||
}
|
||||
render_track_context();
|
||||
update_build_tools();
|
||||
tape_update();
|
||||
update_track_intent();
|
||||
draw_track_hover();
|
||||
draw_track_set();
|
||||
draw_track_spread();
|
||||
draw_build_overlay();
|
||||
draw_track_intent();
|
||||
draw_tape();
|
||||
m_speed.update();
|
||||
m_joints.update();
|
||||
draw_track_hints();
|
||||
@@ -6447,7 +6449,9 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
// the first Esc drops what is going on in the track mode, the next one goes back to the selection
|
||||
if (is_press(Action) && ui()->mode() == nodebank_panel::TRACK)
|
||||
{
|
||||
if (m_lay.active && false == m_lay.points.empty())
|
||||
if (m_tape.active)
|
||||
m_tape = {};
|
||||
else if (m_lay.active && false == m_lay.points.empty())
|
||||
lay_cancel();
|
||||
else if (m_track_style.picking)
|
||||
m_track_style.picking = false;
|
||||
|
||||
@@ -1580,7 +1580,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
void draw_track_hover() const;
|
||||
struct track_intent
|
||||
{
|
||||
enum class kind { none, gizmo, select, point, box, straight_set, straight_break, detour, straight_tool, straight_handle, route_vertex, route_grip, switch_at, lay, lay_end, sweep, turntable_place, turntable_exit, turntable_fit, spread, extend_end, signal_place, signal_move, switch_slide, pick_style, fouling };
|
||||
enum class kind { none, gizmo, select, point, box, straight_set, straight_break, detour, straight_tool, straight_handle, route_vertex, route_grip, switch_at, lay, lay_end, sweep, turntable_place, turntable_exit, turntable_fit, spread, extend_end, signal_place, signal_move, switch_slide, pick_style, fouling, measure };
|
||||
kind what{kind::none};
|
||||
TTrack *track{nullptr};
|
||||
int path{0};
|
||||
@@ -1591,6 +1591,17 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
std::string action;
|
||||
};
|
||||
track_intent m_intent;
|
||||
// the measure between two points (M): on the ground, at a free end or on the axis of the track under the cursor
|
||||
struct tape_state
|
||||
{
|
||||
bool active{false};
|
||||
std::vector<glm::dvec3> points;
|
||||
glm::dvec3 mouse{0.0};
|
||||
};
|
||||
tape_state m_tape;
|
||||
void tape_update();
|
||||
std::string tape_readout() const;
|
||||
void draw_tape() const;
|
||||
track_intent track_intent_at(int const Mods);
|
||||
bool track_gesture_on() const;
|
||||
void update_track_intent();
|
||||
|
||||
@@ -396,6 +396,23 @@ editor_mode::selftest_result editor_mode::selftest_track(std::string const &comm
|
||||
WriteLog(format("SELFTEST vprofile zone %.3f %.3f %s", zone.from, zone.to, zone.name.c_str()));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "tape")
|
||||
{
|
||||
// the measure between two points on the ground, as two clicks of the measuring tape take it
|
||||
std::vector<glm::dvec3> points;
|
||||
for (glm::dvec3 point{0.0, 5000.0, 0.0}; words >> point.x >> point.z;)
|
||||
points.push_back(point);
|
||||
std::vector<char> found;
|
||||
auto const heights{ground_heights(points, true, &found)};
|
||||
for (std::size_t i = 0; i < points.size(); ++i)
|
||||
points[i].y = found[i] != 0 ? heights[i] : 0.0;
|
||||
m_tape = {true, points, points.empty() ? glm::dvec3{0.0} : points.back()};
|
||||
auto readout{tape_readout()};
|
||||
std::replace(readout.begin(), readout.end(), '\n', '|');
|
||||
WriteLog("SELFTEST tape: " + readout);
|
||||
m_tape = {};
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "trackcolours")
|
||||
{
|
||||
int colouring{0};
|
||||
|
||||
@@ -501,6 +501,11 @@ void editor_mode::arm_switch()
|
||||
|
||||
bool editor_mode::track_shortcut(int const Key)
|
||||
{
|
||||
if (Key == GLFW_KEY_M)
|
||||
{
|
||||
m_tape = {false == m_tape.active, {}, m_tape.mouse};
|
||||
return true;
|
||||
}
|
||||
auto const key{Key == GLFW_KEY_C ? GLFW_KEY_G : Key};
|
||||
for (auto const &mode : track_modes())
|
||||
{
|
||||
@@ -531,6 +536,8 @@ bool editor_mode::track_busy() const
|
||||
|
||||
std::string editor_mode::track_mode_name() const
|
||||
{
|
||||
if (m_tape.active)
|
||||
return STR_C("Measure");
|
||||
if (false == m_track_window_open)
|
||||
return STR_C("Select");
|
||||
switch (m_track_tab)
|
||||
@@ -1750,6 +1757,8 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
|
||||
// values of the change in progress, shown next to the cursor
|
||||
std::string editor_mode::track_readout() const
|
||||
{
|
||||
if (m_tape.active)
|
||||
return tape_readout();
|
||||
auto const name = [](TTrack const *Track) { return name_of(*Track); };
|
||||
auto const azimuth = [](glm::dvec3 const &From, glm::dvec3 const &To) {
|
||||
auto const degrees{glm::degrees(std::atan2(To.x - From.x, To.z - From.z))};
|
||||
|
||||
@@ -392,6 +392,11 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
};
|
||||
auto *selected{selected_track()};
|
||||
|
||||
if (m_tape.active)
|
||||
{
|
||||
intent.position = m_tape.mouse;
|
||||
return make(kind::measure, m_tape.points.size() == 1 ? "Click: the end of the measure" : "Click: the start of the measure. M or Esc: done");
|
||||
}
|
||||
if (m_lay.active)
|
||||
{
|
||||
auto const &lay{m_lay};
|
||||
@@ -637,11 +642,75 @@ void editor_mode::update_track_intent()
|
||||
}
|
||||
}
|
||||
|
||||
void editor_mode::tape_update()
|
||||
{
|
||||
auto &tape{m_tape};
|
||||
if (false == tape.active || ImGui::GetIO().WantCaptureMouse)
|
||||
return;
|
||||
glm::vec2 const cursor{ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y};
|
||||
auto const ground{cursor_ground()};
|
||||
if (auto const end{snap_free_end(ground, cursor, nullptr, kRailCategory, {})}; end.track != nullptr)
|
||||
tape.mouse = end.position;
|
||||
else if (auto const under{track_under_cursor()}; under.track != nullptr)
|
||||
tape.mouse = under.point;
|
||||
else
|
||||
tape.mouse = ground;
|
||||
}
|
||||
|
||||
std::string editor_mode::tape_readout() const
|
||||
{
|
||||
auto const &tape{m_tape};
|
||||
if (tape.points.empty())
|
||||
return {};
|
||||
auto const &from{tape.points.front()};
|
||||
auto const &to{tape.points.size() >= 2 ? tape.points[1] : tape.mouse};
|
||||
auto const plan{geometry::plan_distance(from, to)};
|
||||
auto const rise{to.y - from.y};
|
||||
auto azimuth{glm::degrees(std::atan2(to.x - from.x, to.z - from.z))};
|
||||
if (azimuth < 0.0)
|
||||
azimuth += 360.0;
|
||||
auto text{format(STR_C("%.2f m in plan, %.2f m in space"), plan, glm::distance(from, to))};
|
||||
text += "\n" + format(STR_C("height %+.2f m"), rise) + (plan > 0.01 ? format(STR_C(" grade %+.1f per mille"), rise / plan * 1000.0) : std::string{});
|
||||
text += "\n" + format(STR_C("azimuth %.1f deg"), azimuth);
|
||||
if (tape.points.size() >= 2)
|
||||
text += "\n" + STR("Click: a new measure. M or Esc: done");
|
||||
return text;
|
||||
}
|
||||
|
||||
void editor_mode::draw_tape() const
|
||||
{
|
||||
auto const &tape{m_tape};
|
||||
if (false == tape.active)
|
||||
return;
|
||||
screen_projection const projection;
|
||||
auto *drawlist{ImGui::GetForegroundDrawList(ImGui::GetMainViewport())};
|
||||
auto const colour{IM_COL32(255, 230, 60, 255)};
|
||||
std::vector<glm::dvec3> points{tape.points};
|
||||
if (points.size() < 2)
|
||||
points.push_back(tape.mouse);
|
||||
for (std::size_t i = 0; i + 1 < points.size(); ++i)
|
||||
projection.line(drawlist, points[i], points[i + 1], colour, 2.0f);
|
||||
for (auto const &point : points)
|
||||
{
|
||||
ImVec2 screen;
|
||||
if (projection.project(point, screen))
|
||||
{
|
||||
drawlist->AddCircleFilled(screen, 4.0f, colour);
|
||||
drawlist->AddCircle(screen, 7.0f, IM_COL32(0, 0, 0, 200), 12, 1.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void editor_mode::track_press(track_intent const &Intent)
|
||||
{
|
||||
using kind = track_intent::kind;
|
||||
switch (Intent.what)
|
||||
{
|
||||
case kind::measure:
|
||||
if (m_tape.points.size() >= 2)
|
||||
m_tape.points.clear();
|
||||
m_tape.points.push_back(m_tape.mouse);
|
||||
return;
|
||||
case kind::lay_end:
|
||||
if (m_lay.points.empty() && start_extend(Intent.snap))
|
||||
return;
|
||||
|
||||
@@ -10129,3 +10129,24 @@ msgstr "Opisy torów w widoku z góry"
|
||||
|
||||
msgid "Zoomed in from above, the curves get their radius and length and the switches their name and type, as on a plan; where they'd crowd, some are left out"
|
||||
msgstr "Po przybliżeniu z góry łuki dostają promień i długość, a rozjazdy nazwę i typ, jak na planie; gdzie byłoby ich za gęsto, część się chowa"
|
||||
|
||||
msgid "%.2f m in plan, %.2f m in space"
|
||||
msgstr "%.2f m w planie, %.2f m w przestrzeni"
|
||||
|
||||
msgid "height %+.2f m"
|
||||
msgstr "różnica wysokości %+.2f m"
|
||||
|
||||
msgid "azimuth %.1f deg"
|
||||
msgstr "azymut %.1f°"
|
||||
|
||||
msgid "Click: a new measure. M or Esc: done"
|
||||
msgstr "LPM: nowy pomiar. M albo Esc: koniec"
|
||||
|
||||
msgid "Click: the end of the measure"
|
||||
msgstr "LPM: koniec pomiaru"
|
||||
|
||||
msgid "Click: the start of the measure. M or Esc: done"
|
||||
msgstr "LPM: początek pomiaru. M albo Esc: koniec"
|
||||
|
||||
msgid "Measure"
|
||||
msgstr "Miarka"
|
||||
|
||||
Reference in New Issue
Block a user