17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-26 18:14:55 +01:00

feat(editor): the tracks of the track mode can be coloured by their radius, speed or grade, with a legend

View > Track colours draws the rail tracks over the view in bands of the radius of their paths, of their speed or of the grade
along them, from above over the whole view and in the 3D view within 1.5 km of the camera, with the legend of the bands in
the bottom right corner. Plain keeps the lines of the top view as they were. Self-test command trackcolours.
This commit is contained in:
maj00r
2026-10-21 17:47:42 +02:00
parent 27ea2a7456
commit 6a5f0d735d
5 changed files with 125 additions and 4 deletions

View File

@@ -1458,7 +1458,10 @@ bool editor_mode::update()
render_track_inspector();
if (ui()->mode() == nodebank_panel::TRACK)
{
draw_track_lines();
draw_track_legend();
}
if (selected_track())
draw_track_overlay();
if (route_active())
@@ -3579,6 +3582,16 @@ void editor_mode::render_view_menu()
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("Off: the top view draws the rails and sleepers of the tracks without the ballast, so the ground under them shows"));
if (ImGui::BeginMenu(STR_C("Track colours")))
{
char const *const names[]{"Plain", "By the radius", "By the speed", "By the grade"};
for (int i = 0; i < 4; ++i)
if (ImGui::MenuItem(STR_C(names[i]), nullptr, static_cast<int>(m_track_colouring) == i))
m_track_colouring = static_cast<track_colouring>(i);
ImGui::EndMenu();
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("The tracks of the track mode coloured by their radius, speed or grade, with the legend in the corner"));
ImGui::MenuItem(STR_C("Show lanes"), nullptr, &m_roadtool.lanes);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("The lanes of the roads drawn as the paths the vehicles take"));

View File

@@ -1570,6 +1570,10 @@ class editor_mode : public application_mode, private editor_track::observer, pri
track_hover split_spot() const;
void update_track_hover();
void draw_track_lines() const;
// what the colours of the tracks in the view tell
enum class track_colouring { plain, radius, speed, grade };
track_colouring m_track_colouring{track_colouring::plain};
void draw_track_legend() const;
void draw_track_hover() const;
struct track_intent
{

View File

@@ -396,6 +396,13 @@ 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 == "trackcolours")
{
int colouring{0};
words >> colouring;
m_track_colouring = static_cast<track_colouring>(std::clamp(colouring, 0, 3));
return selftest_result::handled;
}
if (command == "vprofilerun" || command == "vprofiledel" || command == "vprofileput")
{
// the grade line of the line through a track, a point of it taken out as with Del, the line applied

View File

@@ -36,6 +36,7 @@ http://mozilla.org/MPL/2.0/.
#include <cctype>
#include <chrono>
#include <cmath>
#include <limits>
namespace
{
@@ -82,6 +83,31 @@ double ortho_metres_per_pixel()
return Global.EditorOrtho && height > 0.0f ? 2.0 * static_cast<double>(Global.EditorOrthoExtent) / static_cast<double>(height) : 0.0;
}
// the bands of the colouring of the tracks: up to the value, the colour and its label in the legend
struct colour_band
{
double below;
ImU32 colour;
char const *label;
};
double constexpr kBeyond{std::numeric_limits<double>::max()};
ImU32 const kUncoloured{IM_COL32(200, 200, 200, 170)};
double const kColouredReach{1500.0}; // m around the camera in the 3D view
std::vector<colour_band> const kRadiusBands{{300.0, IM_COL32(235, 60, 60, 235), "R < 300 m"}, {600.0, IM_COL32(245, 140, 50, 235), "R 300-600 m"}, {1200.0, IM_COL32(240, 220, 60, 235), "R 600-1200 m"},
{3000.0, IM_COL32(110, 210, 80, 235), "R 1200-3000 m"}, {kBeyond, IM_COL32(70, 190, 235, 235), "R > 3000 m"}};
std::vector<colour_band> const kSpeedBands{{40.5, IM_COL32(235, 60, 60, 235), "<= 40 km/h"}, {60.5, IM_COL32(245, 140, 50, 235), "50-60 km/h"}, {80.5, IM_COL32(240, 220, 60, 235), "70-80 km/h"},
{100.5, IM_COL32(110, 210, 80, 235), "90-100 km/h"}, {120.5, IM_COL32(70, 190, 235, 235), "110-120 km/h"}, {kBeyond, IM_COL32(170, 120, 255, 235), "> 120 km/h"}};
std::vector<colour_band> const kGradeBands{{2.0, kUncoloured, "0-2 \xe2\x80\xb0"}, {5.0, IM_COL32(110, 210, 80, 235), "2-5 \xe2\x80\xb0"}, {10.0, IM_COL32(240, 220, 60, 235), "5-10 \xe2\x80\xb0"},
{20.0, IM_COL32(245, 140, 50, 235), "10-20 \xe2\x80\xb0"}, {kBeyond, IM_COL32(235, 60, 60, 235), "> 20 \xe2\x80\xb0"}};
ImU32 band_colour(std::vector<colour_band> const &Bands, double const Value)
{
for (auto const &band : Bands)
if (Value < band.below)
return band.colour;
return kUncoloured;
}
bool plan_near(bezier const &Curve, glm::dvec2 const &Point, double const Reach)
{
auto const centre{(plan_of(Curve.p0) + plan_of(Curve.p1) + plan_of(Curve.p2) + plan_of(Curve.p3)) * 0.25};
@@ -172,34 +198,87 @@ void editor_mode::update_track_hover()
void editor_mode::draw_track_lines() const
{
auto const metres{ortho_metres_per_pixel()};
if (metres < kLinesFrom)
auto const colouring{m_track_colouring};
if (metres < kLinesFrom && colouring == track_colouring::plain)
return;
auto const &io{ImGui::GetIO()};
screen_projection const projection;
glm::dvec2 const centre{Global.pCamera.Pos.x, Global.pCamera.Pos.z};
auto const reach{0.5 * metres * std::hypot(static_cast<double>(io.DisplaySize.x), static_cast<double>(io.DisplaySize.y))};
auto const reach{Global.EditorOrtho ? 0.5 * metres * std::hypot(static_cast<double>(io.DisplaySize.x), static_cast<double>(io.DisplaySize.y)) : kColouredReach};
auto const width{colouring == track_colouring::plain ? 1.5f : 3.0f};
auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())};
for (auto *track : simulation::Paths.sequence())
{
if (track == nullptr || false == rail(*track))
continue;
auto const velocity{editor_track::velocity(*track)};
for (auto const &path : track->m_paths)
{
bezier const curve{path};
if (false == plan_near(curve, centre, reach))
continue;
auto const count{std::clamp(static_cast<int>(curve.plan_length(4) / metres / 8.0), 1, 32)};
auto colour{IM_COL32(235, 235, 235, 150)};
if (colouring == track_colouring::radius)
{
auto const radius{::track_mode::piece_plan_radius(path)};
colour = radius >= 0.5 ? band_colour(kRadiusBands, radius) : kUncoloured;
}
else if (colouring == track_colouring::speed)
colour = velocity > 0.0 ? band_colour(kSpeedBands, velocity) : kUncoloured;
auto const length{curve.plan_length(4)};
auto const count{std::clamp(static_cast<int>(length / std::max(metres, 0.5) / 8.0), colouring == track_colouring::grade ? std::clamp(static_cast<int>(length / 10.0), 1, 8) : 1, 32)};
auto previous{curve.point(0.0)};
for (int k = 1; k <= count; ++k)
{
auto const next{curve.point(static_cast<double>(k) / count)};
projection.line(drawlist, previous, next, IM_COL32(235, 235, 235, 150), 1.5f);
if (colouring == track_colouring::grade)
{
auto const run{geometry::plan_distance(previous, next)};
colour = run > 1e-3 ? band_colour(kGradeBands, std::abs(next.y - previous.y) / run * 1000.0) : kUncoloured;
}
projection.line(drawlist, previous, next, colour, width);
previous = next;
}
}
}
}
void editor_mode::draw_track_legend() const
{
if (m_track_colouring == track_colouring::plain)
return;
auto const &bands{m_track_colouring == track_colouring::radius ? kRadiusBands : m_track_colouring == track_colouring::speed ? kSpeedBands : kGradeBands};
std::vector<std::pair<ImU32, std::string>> rows;
for (auto const &band : bands)
rows.emplace_back(band.colour, band.label);
if (m_track_colouring == track_colouring::radius)
rows.emplace_back(kUncoloured, STR("straight"));
else if (m_track_colouring == track_colouring::speed)
rows.emplace_back(kUncoloured, STR("no limit"));
char const *const titles[]{"", "By the radius", "By the speed", "By the grade"};
std::string const title{STR_C(titles[static_cast<int>(m_track_colouring)])};
auto const line{ImGui::GetTextLineHeightWithSpacing()};
auto const swatch{ImGui::GetTextLineHeight()};
float width{ImGui::CalcTextSize(title.c_str()).x};
for (auto const &row : rows)
width = std::max(width, swatch + 6.0f + ImGui::CalcTextSize(row.second.c_str()).x);
auto const pad{8.0f};
// in the bottom right corner, over the profile strip when it's open
auto const bottom{m_profile.strip_top > editor_ui::view_min().y + 4.0f * line ? std::min(editor_ui::view_max().y, m_profile.strip_top) : editor_ui::view_max().y};
ImVec2 const to{editor_ui::view_max().x - 12.0f, bottom - 12.0f};
ImVec2 const from{to.x - width - pad * 2.0f, to.y - pad * 2.0f - line * static_cast<float>(rows.size() + 1)};
auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())};
drawlist->AddRectFilled(from, to, IM_COL32(0, 0, 0, 170), 4.0f);
ImVec2 at{from.x + pad, from.y + pad};
drawlist->AddText(at, IM_COL32(255, 255, 255, 235), title.c_str());
for (auto const &row : rows)
{
at.y += line;
drawlist->AddRectFilled(ImVec2(at.x, at.y + 2.0f), ImVec2(at.x + swatch, at.y + swatch - 2.0f), row.first, 2.0f);
drawlist->AddText(ImVec2(at.x + swatch + 6.0f, at.y), IM_COL32(235, 235, 235, 235), row.second.c_str());
}
}
void editor_mode::draw_track_hover() const
{
using kind = track_intent::kind;

View File

@@ -10105,3 +10105,21 @@ msgstr "pochylenie %+.1f‰"
msgid "Switched off in this build of the simulator"
msgstr "Wyłączone w tej wersji symulatora"
msgid "Track colours"
msgstr "Kolory torów"
msgid "Plain"
msgstr "Zwykłe"
msgid "By the radius"
msgstr "Według promienia"
msgid "By the speed"
msgstr "Według prędkości"
msgid "By the grade"
msgstr "Według pochylenia"
msgid "The tracks of the track mode coloured by their radius, speed or grade, with the legend in the corner"
msgstr "Tory w dziale Tory pokolorowane według promienia, prędkości albo pochylenia, z legendą w rogu"