mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-12 15:11:01 +01:00
feat(editor): laying track for a beginner: Ctrl+Z and Backspace during a chain of laid pieces go back to the end of the piece before instead of carrying on from a removed track (Ctrl+Y ends the chain); every warning of the laid shape and of a join is shown by the cursor for 4 s after the click, also when the radius chosen on the wheel didn't reach the cursor and the arc goes through it, the preview of a shape with a warning is orange as it is laid anyway; the switch type stays chosen after a switch is placed; the status says each click lays a piece; a "First steps" window (Help menu, opens with the editor until unticked) with eight steps ticked off as they are done; an empty scenery opens in Tracks with the camera over its origin and a grid where there is no ground under the cursor; F1 lists the laying gestures (Ctrl/Shift+wheel, drag from a free end, typed length); self-test command laychain; Polish translation
This commit is contained in:
@@ -931,6 +931,7 @@ void editor_mode::restore_terrain(EditorSnapshot &Snapshot)
|
|||||||
|
|
||||||
void editor_mode::undo_last()
|
void editor_mode::undo_last()
|
||||||
{
|
{
|
||||||
|
first_step_done(first_step::undo);
|
||||||
// a change of the terrain made a moment ago is a step of its own before it's taken back
|
// a change of the terrain made a moment ago is a step of its own before it's taken back
|
||||||
m_history_busy = true;
|
m_history_busy = true;
|
||||||
terrain_history_step();
|
terrain_history_step();
|
||||||
@@ -1478,6 +1479,7 @@ bool editor_mode::update()
|
|||||||
render_new_scenery_popup();
|
render_new_scenery_popup();
|
||||||
render_open_scenery_popup();
|
render_open_scenery_popup();
|
||||||
render_shortcuts_window();
|
render_shortcuts_window();
|
||||||
|
render_first_steps();
|
||||||
render_orthophoto_window();
|
render_orthophoto_window();
|
||||||
render_environment_window();
|
render_environment_window();
|
||||||
draw_selection_overlay();
|
draw_selection_overlay();
|
||||||
@@ -2906,6 +2908,7 @@ bool editor_mode::save()
|
|||||||
ui()->set_status(STR("The scenery wasn't opened for editing. Start the simulator with: -edit <scenery file>"), true);
|
ui()->set_status(STR("The scenery wasn't opened for editing. Start the simulator with: -edit <scenery file>"), true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
first_step_done(first_step::save);
|
||||||
|
|
||||||
// the heightmap terrain is kept in files of its own, the scenery only needs the directive which loads it
|
// the heightmap terrain is kept in files of its own, the scenery only needs the directive which loads it
|
||||||
std::vector<std::string> rootstatements;
|
std::vector<std::string> rootstatements;
|
||||||
@@ -4582,9 +4585,66 @@ void editor_mode::render_help_menu()
|
|||||||
ImGui::MenuItem(STR_C("Keyboard shortcuts"), "F1", &m_shortcuts_open);
|
ImGui::MenuItem(STR_C("Keyboard shortcuts"), "F1", &m_shortcuts_open);
|
||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
ImGui::SetTooltip("%s", STR_C("The keys of the editor, for each field of work"));
|
ImGui::SetTooltip("%s", STR_C("The keys of the editor, for each field of work"));
|
||||||
|
ImGui::MenuItem(STR_C("First steps"), nullptr, &m_first_steps_open);
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
ImGui::SetTooltip("%s", STR_C("Laying the first track, step by step"));
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void editor_mode::first_step_done(first_step const Step)
|
||||||
|
{
|
||||||
|
m_first_steps_done[static_cast<std::size_t>(Step)] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void editor_mode::render_first_steps()
|
||||||
|
{
|
||||||
|
if (false == m_first_steps_open)
|
||||||
|
return;
|
||||||
|
if (ui()->mode() == nodebank_panel::TRACK)
|
||||||
|
first_step_done(first_step::tracks);
|
||||||
|
if (m_lay.active)
|
||||||
|
first_step_done(first_step::lay);
|
||||||
|
static char const *const steps[]{
|
||||||
|
"F3: the Tracks field of work",
|
||||||
|
"L: lay track",
|
||||||
|
"Click on the ground, then once more: a straight. Each next click lays a piece and goes on from its end, Esc ends",
|
||||||
|
"While laying on: Ctrl+wheel changes the radius, Shift+wheel the shape (arc then straight, straight then arc, arc, straight). The plain wheel zooms",
|
||||||
|
"Joining: press on a free end (magenta ring) and drag onto another free end",
|
||||||
|
"T: switch. Click a straight, then press on it and drag: along sets the direction, sideways the side",
|
||||||
|
"Ctrl+Z takes a step back, Backspace while laying takes back the last piece",
|
||||||
|
"Ctrl+S saves the scenery"};
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(440.0f * Global.ui_scale, 0.0f), ImGuiCond_FirstUseEver);
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(8.0f, ImGui::GetIO().DisplaySize.y - 8.0f), ImGuiCond_FirstUseEver, ImVec2(0.0f, 1.0f));
|
||||||
|
ImGui::SetNextWindowBgAlpha(1.0f);
|
||||||
|
if (ImGui::Begin((std::string(STR_C("First steps")) + "###firststeps").c_str(), &m_first_steps_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGui::PushTextWrapPos(420.0f * Global.ui_scale);
|
||||||
|
ImGui::TextDisabled("%s", STR_C("The ticks fill in by themselves, the window doesn't stop anything"));
|
||||||
|
for (std::size_t i = 0; i < m_first_steps_done.size(); ++i)
|
||||||
|
{
|
||||||
|
bool const done{m_first_steps_done[i]};
|
||||||
|
ImGui::TextColored(done ? ImVec4(0.4f, 0.9f, 0.4f, 1.0f) : ImGui::GetStyleColorVec4(ImGuiCol_Text), "%s", done ? "[x]" : "[ ]");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (done)
|
||||||
|
ImGui::TextDisabled("%s", STR_C(steps[i]));
|
||||||
|
else
|
||||||
|
ImGui::TextWrapped("%s", STR_C(steps[i]));
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextDisabled("%s", STR_C("RMB held + W S A D: fly the camera, F: fly to the selected, F1: all the keys"));
|
||||||
|
if (ui()->mode() == nodebank_panel::TRACK && false == GfxRenderer->Mouse_Hit())
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.2f, 1.0f), "%s", STR_C("No ground under the cursor: track goes onto the level 0 plane, drawn as a grid. Terrain: F5"));
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
bool show{EditorSettings.first_steps()};
|
||||||
|
if (ImGui::Checkbox(STR_C("Show when the editor opens"), &show))
|
||||||
|
{
|
||||||
|
EditorSettings.first_steps(show);
|
||||||
|
EditorSettings.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
void editor_mode::render_shortcuts_window()
|
void editor_mode::render_shortcuts_window()
|
||||||
{
|
{
|
||||||
if (false == m_shortcuts_open)
|
if (false == m_shortcuts_open)
|
||||||
@@ -4640,7 +4700,12 @@ void editor_mode::render_shortcuts_window()
|
|||||||
{"Shift+LMB", "Add a track to the selection, drag: a box"},
|
{"Shift+LMB", "Add a track to the selection, drag: a box"},
|
||||||
{"RMB on a track", "What can be done with it"},
|
{"RMB on a track", "What can be done with it"},
|
||||||
{"K", "Split the selected track at the cursor"},
|
{"K", "Split the selected track at the cursor"},
|
||||||
{"Enter / Backspace", "Laying track: finish / take the last point back"},
|
{"L, LMB, LMB...", "Lay track: each click lays a piece and goes on from its end"},
|
||||||
|
{"Drag from a free end", "Lead a track out of it; onto another free end: join the two"},
|
||||||
|
{"Ctrl+wheel", "Laying: radius"},
|
||||||
|
{"Shift+wheel", "Laying: arc then straight, straight then arc, arc, straight; at a free end: another way to join"},
|
||||||
|
{"0-9 while laying", "Type the length (or the radius) of the next piece, Enter lays it"},
|
||||||
|
{"Enter / Backspace", "Laying track: lay up to the cursor / take the last piece back"},
|
||||||
{"Del", "Delete the selected tracks"}}},
|
{"Del", "Delete the selected tracks"}}},
|
||||||
{"Roads",
|
{"Roads",
|
||||||
{{"Esc", "Finish the road being built"},
|
{{"Esc", "Finish the road being built"},
|
||||||
@@ -5150,6 +5215,19 @@ void editor_mode::enter()
|
|||||||
WriteLog("Editor: camera at the first track, " + track->name());
|
WriteLog("Editor: camera at the first track, " + track->name());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (false == m_saved_camera.has_value() && simulation::Paths.sequence().empty())
|
||||||
|
{
|
||||||
|
std::vector<char> found;
|
||||||
|
auto const ground{ground_heights({glm::dvec3{0.0, 5000.0, 0.0}}, true, &found).front()};
|
||||||
|
Camera.Pos = glm::dvec3{0.0, (found.front() != 0 ? ground : 0.0) + 60.0, 60.0};
|
||||||
|
Camera.Angle = glm::vec3(glm::radians(-45.0f), 0.0f, 0.0f);
|
||||||
|
Camera.m_owner = nullptr;
|
||||||
|
FreeFlyModeFlag = true;
|
||||||
|
Global.pCamera = Camera;
|
||||||
|
choose_work_area(work_area::tracks);
|
||||||
|
WriteLog("Editor: camera over the origin of the empty scenery");
|
||||||
|
}
|
||||||
|
m_first_steps_open = EditorSettings.first_steps();
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.ControlPicking = true;
|
Global.ControlPicking = true;
|
||||||
@@ -5458,11 +5536,7 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
|||||||
if (is_press(Action) && ui()->mode() == nodebank_panel::FILL && !m_fill_points.empty())
|
if (is_press(Action) && ui()->mode() == nodebank_panel::FILL && !m_fill_points.empty())
|
||||||
m_fill_points.pop_back();
|
m_fill_points.pop_back();
|
||||||
if (is_press(Action) && ui()->mode() == nodebank_panel::TRACK && m_lay.active && !m_lay.points.empty())
|
if (is_press(Action) && ui()->mode() == nodebank_panel::TRACK && m_lay.active && !m_lay.points.empty())
|
||||||
{
|
lay_back();
|
||||||
m_lay.points.pop_back();
|
|
||||||
if (m_lay.points.empty())
|
|
||||||
m_lay.start = {};
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GLFW_KEY_ENTER:
|
case GLFW_KEY_ENTER:
|
||||||
|
|||||||
@@ -252,6 +252,11 @@ class editor_mode : public application_mode, private editor_track::observer
|
|||||||
void render_help_menu();
|
void render_help_menu();
|
||||||
void render_shortcuts_window();
|
void render_shortcuts_window();
|
||||||
bool m_shortcuts_open{false};
|
bool m_shortcuts_open{false};
|
||||||
|
enum class first_step { tracks, lay, laid, wheel, join, turnout, undo, save, count };
|
||||||
|
void render_first_steps();
|
||||||
|
void first_step_done(first_step const Step);
|
||||||
|
bool m_first_steps_open{false};
|
||||||
|
std::array<bool, static_cast<std::size_t>(first_step::count)> m_first_steps_done{};
|
||||||
// deletes what's selected: a road piece or point, a signal, an include of a scenery template, a model, tracks (Del)
|
// deletes what's selected: a road piece or point, a signal, an include of a scenery template, a model, tracks (Del)
|
||||||
void delete_selected();
|
void delete_selected();
|
||||||
void delete_model(TAnimModel *Model, bool const Joined);
|
void delete_model(TAnimModel *Model, bool const Joined);
|
||||||
@@ -1092,8 +1097,17 @@ class editor_mode : public application_mode, private editor_track::observer
|
|||||||
bool copy_selected{false};
|
bool copy_selected{false};
|
||||||
editor_track::path_style style;
|
editor_track::path_style style;
|
||||||
std::string status;
|
std::string status;
|
||||||
|
double status_time{-100.0};
|
||||||
|
struct step
|
||||||
|
{
|
||||||
|
editor_track::snap_target start;
|
||||||
|
glm::dvec3 point{0.0};
|
||||||
|
};
|
||||||
|
std::vector<step> chain;
|
||||||
};
|
};
|
||||||
lay_tool m_lay;
|
lay_tool m_lay;
|
||||||
|
void lay_after_history(bool const Undo);
|
||||||
|
void lay_back();
|
||||||
void render_lay_ui();
|
void render_lay_ui();
|
||||||
void render_lay_status();
|
void render_lay_status();
|
||||||
void lay_click();
|
void lay_click();
|
||||||
|
|||||||
@@ -1711,6 +1711,43 @@ editor_mode::selftest_result editor_mode::selftest_join(std::string const &comma
|
|||||||
WriteLog(format("SELFTEST %s end: %.3f m from the target", command.c_str(), geometry::plan_distance(previous, b)));
|
WriteLog(format("SELFTEST %s end: %.3f m from the target", command.c_str(), geometry::plan_distance(previous, b)));
|
||||||
return selftest_result::handled;
|
return selftest_result::handled;
|
||||||
}
|
}
|
||||||
|
if (command == "laychain")
|
||||||
|
{
|
||||||
|
int layout{0};
|
||||||
|
words >> layout >> m_lay.radius;
|
||||||
|
m_track_layout = static_cast<track_layout>(std::clamp(layout, 0, 3));
|
||||||
|
m_lay.active = true;
|
||||||
|
lay_cancel();
|
||||||
|
auto const report = [&](std::string const &Step) {
|
||||||
|
auto const *start{m_lay.start.track};
|
||||||
|
WriteLog(format("SELFTEST laychain %s: chain %zu, points %zu, start %s%s at %.2f %.2f, history %zu, status %s", Step.c_str(), m_lay.chain.size(), m_lay.points.size(), start != nullptr ? start->name().c_str() : "-", start != nullptr && start->m_editorremoved ? " (removed)" : "",
|
||||||
|
m_lay.points.empty() ? 0.0 : m_lay.points.front().x, m_lay.points.empty() ? 0.0 : m_lay.points.front().z, m_history.size(), m_lay.status.c_str()));
|
||||||
|
};
|
||||||
|
for (std::string word; words >> word;)
|
||||||
|
{
|
||||||
|
if (word == "b")
|
||||||
|
lay_back();
|
||||||
|
else if (word == "u")
|
||||||
|
undo_last();
|
||||||
|
else if (word == "r")
|
||||||
|
redo_last();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glm::dvec3 point{std::strtod(word.c_str(), nullptr), 5000.0, 0.0};
|
||||||
|
words >> point.z;
|
||||||
|
std::vector<char> found;
|
||||||
|
auto const ground{ground_heights({point}, true, &found)};
|
||||||
|
point.y = found[0] != 0 ? ground[0] : m_lay.points.empty() ? 0.0 : m_lay.points.back().y;
|
||||||
|
m_lay.mouse_snap = editor_track::find_free_end(nullptr, 1, point, 3.0, {});
|
||||||
|
m_lay.mouse = m_lay.mouse_snap.track != nullptr ? point : lay_bed(point);
|
||||||
|
lay_click();
|
||||||
|
word += format(" %.1f", point.z);
|
||||||
|
}
|
||||||
|
report(word);
|
||||||
|
}
|
||||||
|
lay_cancel();
|
||||||
|
return selftest_result::handled;
|
||||||
|
}
|
||||||
if (command == "layclicks")
|
if (command == "layclicks")
|
||||||
{
|
{
|
||||||
int layout{0};
|
int layout{0};
|
||||||
|
|||||||
@@ -77,6 +77,27 @@ double piece_plan_radius(segment_data const &Path)
|
|||||||
return curve.plan_length() / turn;
|
return curve.plan_length() / turn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string lines_of(std::vector<std::string> const &Texts)
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
for (auto const &line : Texts)
|
||||||
|
text += (text.empty() ? "" : "\n") + line;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string narrowed(std::vector<segment_data> const &Pieces, editor_track::layout const Layout, double const Radius)
|
||||||
|
{
|
||||||
|
if (Layout != editor_track::layout::arc_straight && Layout != editor_track::layout::straight_arc)
|
||||||
|
return {};
|
||||||
|
double sharpest{0.0};
|
||||||
|
for (auto const &piece : Pieces)
|
||||||
|
if (auto const radius{piece_plan_radius(piece)}; radius >= 0.5 && (sharpest == 0.0 || radius < sharpest))
|
||||||
|
sharpest = radius;
|
||||||
|
if (sharpest == 0.0 || sharpest >= Radius * 0.99)
|
||||||
|
return {};
|
||||||
|
return format(STR_C("R %.0f m doesn't reach the cursor, the arc goes through it with R %.0f m"), Radius, sharpest);
|
||||||
|
}
|
||||||
|
|
||||||
std::string describe(editor_track::straight const &Line)
|
std::string describe(editor_track::straight const &Line)
|
||||||
{
|
{
|
||||||
return format("L %.2f m az %.4f deg i %.2f per mille %zu paths", Line.length, Line.azimuth, Line.grade * 1000.0, Line.tracks.size());
|
return format("L %.2f m az %.4f deg i %.2f per mille %zu paths", Line.length, Line.azimuth, Line.grade * 1000.0, Line.tracks.size());
|
||||||
@@ -489,6 +510,7 @@ void editor_mode::restore_track_snapshot(EditorSnapshot const &Snapshot, std::ve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lay_after_history(Undo);
|
||||||
m_track_snap = {};
|
m_track_snap = {};
|
||||||
m_track_dirty = false;
|
m_track_dirty = false;
|
||||||
m_track_point = {};
|
m_track_point = {};
|
||||||
@@ -531,6 +553,7 @@ void editor_mode::show_track_tab(track_tab const Tab)
|
|||||||
m_straights.tool = 0;
|
m_straights.tool = 0;
|
||||||
m_lay.points.clear();
|
m_lay.points.clear();
|
||||||
m_lay.start = {};
|
m_lay.start = {};
|
||||||
|
m_lay.chain.clear();
|
||||||
m_lay.preview.clear();
|
m_lay.preview.clear();
|
||||||
m_lay.status.clear();
|
m_lay.status.clear();
|
||||||
m_lay.active = Tab == track_tab::lay;
|
m_lay.active = Tab == track_tab::lay;
|
||||||
@@ -614,7 +637,7 @@ std::string editor_mode::track_mode_name() const
|
|||||||
return STR_C("Select: LMB on a path");
|
return STR_C("Select: LMB on a path");
|
||||||
switch (m_track_tab)
|
switch (m_track_tab)
|
||||||
{
|
{
|
||||||
case track_tab::lay: return m_extend.active ? STR_C("Laying track: new path from the free end") : STR_C("Laying track: LMB adds the points");
|
case track_tab::lay: return m_extend.active ? STR_C("Laying track: new path from the free end") : STR_C("Laying track: each click lays a piece, Esc ends");
|
||||||
case track_tab::turnout:
|
case track_tab::turnout:
|
||||||
if (m_switch.placing)
|
if (m_switch.placing)
|
||||||
return STR_C("Switch: drag to set its direction and side");
|
return STR_C("Switch: drag to set its direction and side");
|
||||||
@@ -3636,7 +3659,7 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
|
|||||||
hints = {{"LMB", chained ? "lay the shape up to here and go on from its end" : "lay the straight up to here and go on from its end"}, {"LMB on a free end", "join and lay"}};
|
hints = {{"LMB", chained ? "lay the shape up to here and go on from its end" : "lay the straight up to here and go on from its end"}, {"LMB on a free end", "join and lay"}};
|
||||||
if (chained || m_lay.mouse_snap.track != nullptr)
|
if (chained || m_lay.mouse_snap.track != nullptr)
|
||||||
hints.insert(hints.end(), {{"Ctrl+wheel", "radius"}, {"Shift+wheel", "arc / straight, at a free end: another shape"}});
|
hints.insert(hints.end(), {{"Ctrl+wheel", "radius"}, {"Shift+wheel", "arc / straight, at a free end: another shape"}});
|
||||||
hints.insert(hints.end(), {{"Enter", "lay up to the cursor"}, {"Backspace", "take back the point"}, {"Esc", "cancel"}});
|
hints.insert(hints.end(), {{"Enter", "lay up to the cursor"}, {"Backspace", m_lay.chain.empty() ? "take back the point" : "take back the last piece"}, {"Esc", "cancel"}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (false == m_straights.detour.empty())
|
else if (false == m_straights.detour.empty())
|
||||||
@@ -3821,6 +3844,8 @@ std::string editor_mode::track_readout() const
|
|||||||
text += "\n" + lay.preview_error;
|
text += "\n" + lay.preview_error;
|
||||||
if (lay.points.size() == 1 && (lay.start.track != nullptr || lay.mouse_snap.track != nullptr))
|
if (lay.points.size() == 1 && (lay.start.track != nullptr || lay.mouse_snap.track != nullptr))
|
||||||
text += "\n" + track_shaping(lay.mouse_snap.track != nullptr && lay.start.track != nullptr);
|
text += "\n" + track_shaping(lay.mouse_snap.track != nullptr && lay.start.track != nullptr);
|
||||||
|
if (false == lay.status.empty() && ImGui::GetTime() - lay.status_time < 4.0)
|
||||||
|
text += "\n" + lay.status;
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
auto const &state{m_straights};
|
auto const &state{m_straights};
|
||||||
@@ -4449,7 +4474,13 @@ std::vector<segment_data> editor_mode::join_pieces(TTrack const *From, editor_tr
|
|||||||
result = std::move(*eased);
|
result = std::move(*eased);
|
||||||
}
|
}
|
||||||
Length = result.length;
|
Length = result.length;
|
||||||
Error = result.kind == alignment::join_kind::bezier ? std::string{STR_C("No curve fits between the ends, they are joined with a free curve")} : std::string{};
|
std::vector<std::string> notes;
|
||||||
|
for (auto const &warning : result.warnings)
|
||||||
|
if (m_join_radius > 0.0 || warning.find("R reduced") == std::string::npos)
|
||||||
|
notes.push_back(warning);
|
||||||
|
if (result.kind == alignment::join_kind::bezier)
|
||||||
|
notes.insert(notes.begin(), STR_C("No curve fits between the ends, they are joined with a free curve"));
|
||||||
|
Error = lines_of(notes);
|
||||||
m_join_last = result;
|
m_join_last = result;
|
||||||
return result.pieces;
|
return result.pieces;
|
||||||
}
|
}
|
||||||
@@ -4514,6 +4545,9 @@ void editor_mode::finish_extend()
|
|||||||
editor_track::commit(created);
|
editor_track::commit(created);
|
||||||
digitize_drawn(created);
|
digitize_drawn(created);
|
||||||
push_track_snapshot({}, created);
|
push_track_snapshot({}, created);
|
||||||
|
first_step_done(first_step::laid);
|
||||||
|
if (target.track != nullptr)
|
||||||
|
first_step_done(first_step::join);
|
||||||
m_node = created.back();
|
m_node = created.back();
|
||||||
ui()->set_node(m_node);
|
ui()->set_node(m_node);
|
||||||
straight_refresh();
|
straight_refresh();
|
||||||
@@ -4621,6 +4655,7 @@ bool editor_mode::track_wheel(double const Offset)
|
|||||||
return *radius;
|
return *radius;
|
||||||
return radii[0];
|
return radii[0];
|
||||||
};
|
};
|
||||||
|
first_step_done(first_step::wheel);
|
||||||
if (io.KeyCtrl)
|
if (io.KeyCtrl)
|
||||||
{
|
{
|
||||||
if (false == joined)
|
if (false == joined)
|
||||||
@@ -4662,6 +4697,7 @@ std::vector<segment_data> editor_mode::lay_pieces(std::vector<glm::dvec3> const
|
|||||||
{
|
{
|
||||||
auto const grade{-grade_of(tool.start.direction)};
|
auto const grade{-grade_of(tool.start.direction)};
|
||||||
pieces = editor_track::layout_pieces(m_track_layout, Points[0], glm::normalize(leaving), grade, Points[1], tool.radius);
|
pieces = editor_track::layout_pieces(m_track_layout, Points[0], glm::normalize(leaving), grade, Points[1], tool.radius);
|
||||||
|
Error = narrowed(pieces, m_track_layout, tool.radius);
|
||||||
follow_ground(pieces, Points[0].y, grade, Points[1].y, std::numeric_limits<double>::quiet_NaN(), tool.start.track);
|
follow_ground(pieces, Points[0].y, grade, Points[1].y, std::numeric_limits<double>::quiet_NaN(), tool.start.track);
|
||||||
}
|
}
|
||||||
else if (End.track == nullptr)
|
else if (End.track == nullptr)
|
||||||
@@ -4675,6 +4711,7 @@ std::vector<segment_data> editor_mode::lay_pieces(std::vector<glm::dvec3> const
|
|||||||
auto const back{editor_track::layout_pieces(m_track_layout, End.position, glm::normalize(-plan_of(End.direction)), -grade_of(End.direction), Points[0], tool.radius)};
|
auto const back{editor_track::layout_pieces(m_track_layout, End.position, glm::normalize(-plan_of(End.direction)), -grade_of(End.direction), Points[0], tool.radius)};
|
||||||
for (auto piece{back.rbegin()}; piece != back.rend(); ++piece)
|
for (auto piece{back.rbegin()}; piece != back.rend(); ++piece)
|
||||||
pieces.push_back(reversed(*piece));
|
pieces.push_back(reversed(*piece));
|
||||||
|
Error = narrowed(pieces, m_track_layout, tool.radius);
|
||||||
follow_ground(pieces, Points[0].y, std::numeric_limits<double>::quiet_NaN(), End.position.y, grade_of(End.direction), End.track);
|
follow_ground(pieces, Points[0].y, std::numeric_limits<double>::quiet_NaN(), End.position.y, grade_of(End.direction), End.track);
|
||||||
}
|
}
|
||||||
for (auto const &piece : pieces)
|
for (auto const &piece : pieces)
|
||||||
@@ -4697,7 +4734,7 @@ std::vector<segment_data> editor_mode::lay_pieces(std::vector<glm::dvec3> const
|
|||||||
Error = shape.errors.empty() ? std::string{STR_C("The track can't be laid through these points")} : shape.errors.front();
|
Error = shape.errors.empty() ? std::string{STR_C("The track can't be laid through these points")} : shape.errors.front();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
Error = shape.warnings.empty() ? std::string{} : shape.warnings.front();
|
Error = lines_of(shape.warnings);
|
||||||
auto const count = [&](alignment::result const &Shape, alignment::design const &Design) {
|
auto const count = [&](alignment::result const &Shape, alignment::design const &Design) {
|
||||||
return std::max(alignment::minimum_pieces(Shape, Design), static_cast<std::size_t>(std::ceil(Shape.length / std::max(5.0, tool.piece_length))));
|
return std::max(alignment::minimum_pieces(Shape, Design), static_cast<std::size_t>(std::ceil(Shape.length / std::max(5.0, tool.piece_length))));
|
||||||
};
|
};
|
||||||
@@ -4734,7 +4771,7 @@ std::vector<segment_data> editor_mode::lay_pieces(std::vector<glm::dvec3> const
|
|||||||
if (easedshape.valid)
|
if (easedshape.valid)
|
||||||
{
|
{
|
||||||
Length = editor_track::eased_length(in, easedshape.length, out);
|
Length = editor_track::eased_length(in, easedshape.length, out);
|
||||||
Error = easedshape.warnings.empty() ? std::string{} : easedshape.warnings.front();
|
Error = lines_of(easedshape.warnings);
|
||||||
return editor_track::eased_pieces(in, alignment::pieces(easedshape, easeddesign, count(easedshape, easeddesign)), out);
|
return editor_track::eased_pieces(in, alignment::pieces(easedshape, easeddesign, count(easedshape, easeddesign)), out);
|
||||||
}
|
}
|
||||||
Error = STR("The curvature changes abruptly where the track joins, there's no room for a transition curve") + (easedshape.errors.empty() ? std::string{} : ": " + easedshape.errors.front());
|
Error = STR("The curvature changes abruptly where the track joins, there's no room for a transition curve") + (easedshape.errors.empty() ? std::string{} : ": " + easedshape.errors.front());
|
||||||
@@ -4803,6 +4840,7 @@ void editor_mode::lay_click()
|
|||||||
}
|
}
|
||||||
if (tool.points.empty())
|
if (tool.points.empty())
|
||||||
{
|
{
|
||||||
|
tool.chain.clear();
|
||||||
tool.start = snap;
|
tool.start = snap;
|
||||||
tool.points.push_back(snap.track != nullptr ? snap.position : tool.mouse);
|
tool.points.push_back(snap.track != nullptr ? snap.position : tool.mouse);
|
||||||
return;
|
return;
|
||||||
@@ -4813,6 +4851,7 @@ void editor_mode::lay_click()
|
|||||||
m_typed.clear();
|
m_typed.clear();
|
||||||
if (tool.points.size() == 1)
|
if (tool.points.size() == 1)
|
||||||
{
|
{
|
||||||
|
lay_tool::step const previous{tool.start, tool.points.front()};
|
||||||
tool.points.push_back(tool.mouse);
|
tool.points.push_back(tool.mouse);
|
||||||
lay_finish({});
|
lay_finish({});
|
||||||
if (false == tool.points.empty())
|
if (false == tool.points.empty())
|
||||||
@@ -4830,6 +4869,7 @@ void editor_mode::lay_click()
|
|||||||
next.position = path.points[segment_data::point::end];
|
next.position = path.points[segment_data::point::end];
|
||||||
auto const &control{path.points[segment_data::point::control2]};
|
auto const &control{path.points[segment_data::point::control2]};
|
||||||
next.direction = glm::normalize(control != glm::dvec3{} ? control : path.points[segment_data::point::start] - next.position);
|
next.direction = glm::normalize(control != glm::dvec3{} ? control : path.points[segment_data::point::start] - next.position);
|
||||||
|
tool.chain.push_back(previous);
|
||||||
tool.start = next;
|
tool.start = next;
|
||||||
tool.points = {next.position};
|
tool.points = {next.position};
|
||||||
return;
|
return;
|
||||||
@@ -4843,6 +4883,7 @@ void editor_mode::lay_finish(editor_track::snap_target const &End)
|
|||||||
double length;
|
double length;
|
||||||
std::string error;
|
std::string error;
|
||||||
auto const pieces{lay_pieces(tool.points, End, length, error)};
|
auto const pieces{lay_pieces(tool.points, End, length, error)};
|
||||||
|
tool.status_time = ImGui::GetTime();
|
||||||
if (pieces.empty())
|
if (pieces.empty())
|
||||||
{
|
{
|
||||||
tool.status = error.empty() ? std::string{STR_C("Click at least two points")} : error;
|
tool.status = error.empty() ? std::string{STR_C("Click at least two points")} : error;
|
||||||
@@ -4859,6 +4900,9 @@ void editor_mode::lay_finish(editor_track::snap_target const &End)
|
|||||||
editor_track::commit(created);
|
editor_track::commit(created);
|
||||||
digitize_drawn(created);
|
digitize_drawn(created);
|
||||||
push_track_snapshot({}, created);
|
push_track_snapshot({}, created);
|
||||||
|
first_step_done(first_step::laid);
|
||||||
|
if (End.track != nullptr)
|
||||||
|
first_step_done(first_step::join);
|
||||||
tool.status = format(STR_C("Laid %zu paths, %.1f m"), created.size(), length);
|
tool.status = format(STR_C("Laid %zu paths, %.1f m"), created.size(), length);
|
||||||
if (false == error.empty())
|
if (false == error.empty())
|
||||||
tool.status += "\n" + error;
|
tool.status += "\n" + error;
|
||||||
@@ -4921,9 +4965,49 @@ void editor_mode::lay_cancel()
|
|||||||
auto &tool{m_lay};
|
auto &tool{m_lay};
|
||||||
tool.points.clear();
|
tool.points.clear();
|
||||||
tool.start = {};
|
tool.start = {};
|
||||||
|
tool.chain.clear();
|
||||||
tool.preview.clear();
|
tool.preview.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void editor_mode::lay_after_history(bool const Undo)
|
||||||
|
{
|
||||||
|
auto &tool{m_lay};
|
||||||
|
if (tool.points.empty())
|
||||||
|
return;
|
||||||
|
if (false == Undo)
|
||||||
|
{
|
||||||
|
lay_cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (tool.start.track != nullptr && tool.start.track->m_editorremoved)
|
||||||
|
{
|
||||||
|
if (tool.chain.empty())
|
||||||
|
{
|
||||||
|
lay_cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tool.start = tool.chain.back().start;
|
||||||
|
tool.points = {tool.chain.back().point};
|
||||||
|
tool.chain.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void editor_mode::lay_back()
|
||||||
|
{
|
||||||
|
auto &tool{m_lay};
|
||||||
|
if (false == tool.chain.empty())
|
||||||
|
{
|
||||||
|
undo_last();
|
||||||
|
tool.status = STR_C("The last piece was taken back");
|
||||||
|
tool.status_time = ImGui::GetTime();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (false == tool.points.empty())
|
||||||
|
tool.points.pop_back();
|
||||||
|
if (tool.points.empty())
|
||||||
|
tool.start = {};
|
||||||
|
}
|
||||||
|
|
||||||
void editor_mode::render_lay_ui()
|
void editor_mode::render_lay_ui()
|
||||||
{
|
{
|
||||||
auto &tool{m_lay};
|
auto &tool{m_lay};
|
||||||
@@ -5136,8 +5220,8 @@ void editor_mode::switch_placed(std::vector<TTrack *> const &Created)
|
|||||||
if (found == Created.end())
|
if (found == Created.end())
|
||||||
return;
|
return;
|
||||||
auto const slip{std::count_if(Created.begin(), Created.end(), [](TTrack const *Track) { return Track != nullptr && Track->eType == tt_Switch; }) > 1};
|
auto const slip{std::count_if(Created.begin(), Created.end(), [](TTrack const *Track) { return Track != nullptr && Track->eType == tt_Switch; }) > 1};
|
||||||
m_switch.armed = -1;
|
|
||||||
m_switch.placing = false;
|
m_switch.placing = false;
|
||||||
|
first_step_done(first_step::turnout);
|
||||||
m_track_point = {};
|
m_track_point = {};
|
||||||
m_node = *found;
|
m_node = *found;
|
||||||
ui()->set_node(m_node);
|
ui()->set_node(m_node);
|
||||||
@@ -5319,6 +5403,27 @@ void editor_mode::draw_build_overlay() const
|
|||||||
previous = next;
|
previous = next;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (false == GfxRenderer->Mouse_Hit() && false == ImGui::GetIO().WantCaptureMouse)
|
||||||
|
{
|
||||||
|
auto const centre{m_lay.active ? m_lay.mouse : cursor_ground()};
|
||||||
|
double const cell{10.0};
|
||||||
|
int const reach{10};
|
||||||
|
glm::dvec3 const origin{std::round(centre.x / cell) * cell, centre.y, std::round(centre.z / cell) * cell};
|
||||||
|
for (int i = -reach; i <= reach; ++i)
|
||||||
|
{
|
||||||
|
auto const major{std::fmod(std::abs(origin.x / cell + i), 10.0) < 0.5};
|
||||||
|
auto const colour{major ? IM_COL32(255, 255, 255, 70) : IM_COL32(255, 255, 255, 35)};
|
||||||
|
for (int j = -reach; j < reach; ++j)
|
||||||
|
projection.line(drawlist, origin + glm::dvec3{i * cell, 0.0, j * cell}, origin + glm::dvec3{i * cell, 0.0, (j + 1) * cell}, colour, 1.0f);
|
||||||
|
}
|
||||||
|
for (int j = -reach; j <= reach; ++j)
|
||||||
|
{
|
||||||
|
auto const major{std::fmod(std::abs(origin.z / cell + j), 10.0) < 0.5};
|
||||||
|
auto const colour{major ? IM_COL32(255, 255, 255, 70) : IM_COL32(255, 255, 255, 35)};
|
||||||
|
for (int i = -reach; i < reach; ++i)
|
||||||
|
projection.line(drawlist, origin + glm::dvec3{i * cell, 0.0, j * cell}, origin + glm::dvec3{(i + 1) * cell, 0.0, j * cell}, colour, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
auto const &display{ImGui::GetIO().DisplaySize};
|
auto const &display{ImGui::GetIO().DisplaySize};
|
||||||
for (auto const *track : simulation::Paths.sequence())
|
for (auto const *track : simulation::Paths.sequence())
|
||||||
{
|
{
|
||||||
@@ -5377,7 +5482,7 @@ void editor_mode::draw_build_overlay() const
|
|||||||
auto const &lay{m_lay};
|
auto const &lay{m_lay};
|
||||||
auto const piece_colour = [&](segment_data const &Path) {
|
auto const piece_colour = [&](segment_data const &Path) {
|
||||||
if (false == lay.preview_error.empty())
|
if (false == lay.preview_error.empty())
|
||||||
return overlay_color::invalid;
|
return overlay_color::warning;
|
||||||
return piece_plan_radius(Path) < 0.5 ? IM_COL32(255, 255, 255, 230) : overlay_color::marked;
|
return piece_plan_radius(Path) < 0.5 ? IM_COL32(255, 255, 255, 230) : overlay_color::marked;
|
||||||
};
|
};
|
||||||
for (auto const &piece : lay.preview)
|
for (auto const &piece : lay.preview)
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
|||||||
return make(kind::lay_end, lay.points.empty() ? "Click: start from this free end, drag: lead a track out of it" : "Click: join this end and lay");
|
return make(kind::lay_end, lay.points.empty() ? "Click: start from this free end, drag: lead a track out of it" : "Click: join this end and lay");
|
||||||
}
|
}
|
||||||
intent.position = lay.mouse;
|
intent.position = lay.mouse;
|
||||||
return make(kind::lay, lay.points.empty() ? "Click: start of the new track" : "Click: next point");
|
return make(kind::lay, lay.points.empty() ? "Click: start of the new track" : "Click: lay the track to here");
|
||||||
}
|
}
|
||||||
if (m_track_tab == track_tab::turntable)
|
if (m_track_tab == track_tab::turntable)
|
||||||
return turntable_intent(ground, shift);
|
return turntable_intent(ground, shift);
|
||||||
@@ -369,7 +369,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
|||||||
{
|
{
|
||||||
case track_tab::straights: return make(kind::select, "Click: the whole straight through this track");
|
case track_tab::straights: return make(kind::select, "Click: the whole straight through this track");
|
||||||
case track_tab::route: return make(kind::select, "Click: the curve of this track with its straights");
|
case track_tab::route: return make(kind::select, "Click: the curve of this track with its straights");
|
||||||
case track_tab::turnout: return make(kind::select, m_hover.track->eType == tt_Switch ? "Click: edit this switch" : m_switch.armed < 0 ? "Click: choose this track, then the type of the switch" : "Click: put a switch into this track");
|
case track_tab::turnout: return make(kind::select, m_hover.track->eType == tt_Switch ? "Click: edit this switch" : m_switch.armed < 0 ? "Click: choose this track, then the type of the switch" : "Click: choose this track, then press and drag on it for the switch");
|
||||||
case track_tab::profile: return make(kind::select, "Click: the grade line through this track");
|
case track_tab::profile: return make(kind::select, "Click: the grade line through this track");
|
||||||
case track_tab::lineside: return make(kind::select, "Click: the line the objects go along");
|
case track_tab::lineside: return make(kind::select, "Click: the line the objects go along");
|
||||||
default: return make(kind::select, "Click: select");
|
default: return make(kind::select, "Click: select");
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ ImU32 constexpr marked{IM_COL32(255, 210, 60, 255)};
|
|||||||
ImU32 constexpr grip{IM_COL32(60, 230, 90, 255)};
|
ImU32 constexpr grip{IM_COL32(60, 230, 90, 255)};
|
||||||
ImU32 constexpr selected{IM_COL32(40, 220, 255, 255)};
|
ImU32 constexpr selected{IM_COL32(40, 220, 255, 255)};
|
||||||
ImU32 constexpr invalid{IM_COL32(255, 60, 60, 255)};
|
ImU32 constexpr invalid{IM_COL32(255, 60, 60, 255)};
|
||||||
|
ImU32 constexpr warning{IM_COL32(255, 140, 40, 255)};
|
||||||
ImU32 constexpr highlight{IM_COL32(255, 255, 255, 255)};
|
ImU32 constexpr highlight{IM_COL32(255, 255, 255, 255)};
|
||||||
} // namespace overlay_color
|
} // namespace overlay_color
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ bool editorSettings::load()
|
|||||||
parse(value, m_nodebank_card);
|
parse(value, m_nodebank_card);
|
||||||
else if (key == "colours")
|
else if (key == "colours")
|
||||||
parse(value, m_palette);
|
parse(value, m_palette);
|
||||||
|
else if (key == "first_steps")
|
||||||
|
m_first_steps = (value == "1");
|
||||||
else if (key.rfind(origin_prefix, 0) == 0)
|
else if (key.rfind(origin_prefix, 0) == 0)
|
||||||
{
|
{
|
||||||
// northing;easting
|
// northing;easting
|
||||||
@@ -145,6 +147,7 @@ bool editorSettings::save()
|
|||||||
stream << "nodebank_previews " << (m_nodebank_previews ? 1 : 0) << "\n";
|
stream << "nodebank_previews " << (m_nodebank_previews ? 1 : 0) << "\n";
|
||||||
stream << "nodebank_card " << m_nodebank_card << "\n";
|
stream << "nodebank_card " << m_nodebank_card << "\n";
|
||||||
stream << "colours " << m_palette << "\n";
|
stream << "colours " << m_palette << "\n";
|
||||||
|
stream << "first_steps " << (m_first_steps ? 1 : 0) << "\n";
|
||||||
stream << std::fixed << std::setprecision(3);
|
stream << std::fixed << std::setprecision(3);
|
||||||
for (auto const &origin : m_orthophoto_origins)
|
for (auto const &origin : m_orthophoto_origins)
|
||||||
stream << origin.first << " " << origin.second.first << ";" << origin.second.second << "\n";
|
stream << origin.first << " " << origin.second.first << ";" << origin.second.second << "\n";
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ public:
|
|||||||
int palette() const { return m_palette; }
|
int palette() const { return m_palette; }
|
||||||
void palette(int Palette) { m_palette = Palette; }
|
void palette(int Palette) { m_palette = Palette; }
|
||||||
|
|
||||||
|
bool first_steps() const { return m_first_steps; }
|
||||||
|
void first_steps(bool Show) { m_first_steps = Show; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
movement_scheme m_movement{movement_scheme::wsad};
|
movement_scheme m_movement{movement_scheme::wsad};
|
||||||
orthophoto_settings m_orthophoto;
|
orthophoto_settings m_orthophoto;
|
||||||
@@ -63,6 +66,7 @@ private:
|
|||||||
bool m_nodebank_previews{true};
|
bool m_nodebank_previews{true};
|
||||||
int m_nodebank_card{96};
|
int m_nodebank_card{96};
|
||||||
int m_palette{0};
|
int m_palette{0};
|
||||||
|
bool m_first_steps{true};
|
||||||
};
|
};
|
||||||
|
|
||||||
// global editor settings instance
|
// global editor settings instance
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ msgstr "Pokaż inspektor"
|
|||||||
msgid "The curve can't be read from this path, edit it as a single path"
|
msgid "The curve can't be read from this path, edit it as a single path"
|
||||||
msgstr "Z tego odcinka nie da się odczytać łuku, edytuj go jako pojedynczy odcinek"
|
msgstr "Z tego odcinka nie da się odczytać łuku, edytuj go jako pojedynczy odcinek"
|
||||||
|
|
||||||
msgid "Laying track: LMB adds the points"
|
msgid "Laying track: each click lays a piece, Esc ends"
|
||||||
msgstr "Układanie toru: LPM dodaje punkty"
|
msgstr "Układanie toru: każdy klik kładzie odcinek, Esc kończy"
|
||||||
|
|
||||||
msgid "Switch: drag to set its direction and side"
|
msgid "Switch: drag to set its direction and side"
|
||||||
msgstr "Rozjazd: przeciągnij, aby ustawić kierunek i stronę"
|
msgstr "Rozjazd: przeciągnij, aby ustawić kierunek i stronę"
|
||||||
@@ -2835,8 +2835,8 @@ msgstr "Klik: dołącz do tego końca i ułóż"
|
|||||||
msgid "Click: start of the new track"
|
msgid "Click: start of the new track"
|
||||||
msgstr "Klik: początek nowego toru"
|
msgstr "Klik: początek nowego toru"
|
||||||
|
|
||||||
msgid "Click: next point"
|
msgid "Click: lay the track to here"
|
||||||
msgstr "Klik: następny punkt"
|
msgstr "Klik: połóż tor do tego miejsca"
|
||||||
|
|
||||||
msgid "Press: where the model starts, drag to its end"
|
msgid "Press: where the model starts, drag to its end"
|
||||||
msgstr "Wciśnij: początek modelu, przeciągnij do jego końca"
|
msgstr "Wciśnij: początek modelu, przeciągnij do jego końca"
|
||||||
@@ -2901,8 +2901,8 @@ msgstr "Klik: edytuj ten rozjazd"
|
|||||||
msgid "Click: choose this track, then the type of the switch"
|
msgid "Click: choose this track, then the type of the switch"
|
||||||
msgstr "Klik: wybierz ten tor, potem typ rozjazdu"
|
msgstr "Klik: wybierz ten tor, potem typ rozjazdu"
|
||||||
|
|
||||||
msgid "Click: put a switch into this track"
|
msgid "Click: choose this track, then press and drag on it for the switch"
|
||||||
msgstr "Klik: wstaw rozjazd w ten tor"
|
msgstr "Klik: wybierz ten tor, potem wciśnij i przeciągnij na nim, by wstawić rozjazd"
|
||||||
|
|
||||||
msgid "Click: the grade line through this track"
|
msgid "Click: the grade line through this track"
|
||||||
msgstr "Klik: niweleta przez ten tor"
|
msgstr "Klik: niweleta przez ten tor"
|
||||||
@@ -4948,8 +4948,8 @@ msgstr "Skróty klawiszowe"
|
|||||||
msgid "Lay track / switch / turntable"
|
msgid "Lay track / switch / turntable"
|
||||||
msgstr "Układanie toru / rozjazd / obrotnica"
|
msgstr "Układanie toru / rozjazd / obrotnica"
|
||||||
|
|
||||||
msgid "Laying track: finish / take the last point back"
|
msgid "Laying track: lay up to the cursor / take the last piece back"
|
||||||
msgstr "Układanie toru: zakończ / cofnij ostatni punkt"
|
msgstr "Układanie toru: połóż do kursora / cofnij ostatni odcinek"
|
||||||
|
|
||||||
msgid "Leave the editor"
|
msgid "Leave the editor"
|
||||||
msgstr "Wyjście z edytora"
|
msgstr "Wyjście z edytora"
|
||||||
@@ -5487,3 +5487,75 @@ msgstr ", ostrzej niż rozjazd (R %.0f m)"
|
|||||||
|
|
||||||
msgid ", the switch moved %.2f m"
|
msgid ", the switch moved %.2f m"
|
||||||
msgstr ", rozjazd przesunięty o %.2f m"
|
msgstr ", rozjazd przesunięty o %.2f m"
|
||||||
|
|
||||||
|
msgid "take back the last piece"
|
||||||
|
msgstr "cofnij ostatni odcinek"
|
||||||
|
|
||||||
|
msgid "The last piece was taken back"
|
||||||
|
msgstr "Ostatni odcinek cofnięty"
|
||||||
|
|
||||||
|
msgid "R %.0f m doesn't reach the cursor, the arc goes through it with R %.0f m"
|
||||||
|
msgstr "R %.0f m nie sięga kursora, łuk przechodzi przez niego z R %.0f m"
|
||||||
|
|
||||||
|
msgid "First steps"
|
||||||
|
msgstr "Pierwsze kroki"
|
||||||
|
|
||||||
|
msgid "Laying the first track, step by step"
|
||||||
|
msgstr "Pierwszy tor krok po kroku"
|
||||||
|
|
||||||
|
msgid "The ticks fill in by themselves, the window doesn't stop anything"
|
||||||
|
msgstr "Kroki odhaczają się same, okno niczego nie blokuje"
|
||||||
|
|
||||||
|
msgid "F3: the Tracks field of work"
|
||||||
|
msgstr "F3: dział Tory"
|
||||||
|
|
||||||
|
msgid "L: lay track"
|
||||||
|
msgstr "L: układanie toru"
|
||||||
|
|
||||||
|
msgid "Click on the ground, then once more: a straight. Each next click lays a piece and goes on from its end, Esc ends"
|
||||||
|
msgstr "Kliknij na terenie, potem jeszcze raz: prosta. Każdy kolejny klik kładzie odcinek i ciągnie tor dalej z jego końca, Esc kończy"
|
||||||
|
|
||||||
|
msgid "While laying on: Ctrl+wheel changes the radius, Shift+wheel the shape (arc then straight, straight then arc, arc, straight). The plain wheel zooms"
|
||||||
|
msgstr "W trakcie układania: Ctrl+kółko zmienia promień, Shift+kółko kształt (łuk i prosta, prosta i łuk, łuk, prosta). Samo kółko przybliża widok"
|
||||||
|
|
||||||
|
msgid "Joining: press on a free end (magenta ring) and drag onto another free end"
|
||||||
|
msgstr "Łączenie: wciśnij na wolnym końcu (różowy pierścień) i przeciągnij na inny wolny koniec"
|
||||||
|
|
||||||
|
msgid "T: switch. Click a straight, then press on it and drag: along sets the direction, sideways the side"
|
||||||
|
msgstr "T: rozjazd. Kliknij prostą, potem wciśnij na niej i przeciągnij: wzdłuż ustala kierunek, w bok stronę"
|
||||||
|
|
||||||
|
msgid "Ctrl+Z takes a step back, Backspace while laying takes back the last piece"
|
||||||
|
msgstr "Ctrl+Z cofa krok, Backspace w trakcie układania cofa ostatni odcinek"
|
||||||
|
|
||||||
|
msgid "Ctrl+S saves the scenery"
|
||||||
|
msgstr "Ctrl+S zapisuje scenerię"
|
||||||
|
|
||||||
|
msgid "RMB held + W S A D: fly the camera, F: fly to the selected, F1: all the keys"
|
||||||
|
msgstr "Wciśnięty PPM + W S A D: lot kamerą, F: leć do zaznaczonego, F1: wszystkie klawisze"
|
||||||
|
|
||||||
|
msgid "No ground under the cursor: track goes onto the level 0 plane, drawn as a grid. Terrain: F5"
|
||||||
|
msgstr "Pod kursorem nie ma terenu: tor trafia na płaszczyznę na wysokości 0, widoczną jako siatka. Teren: F5"
|
||||||
|
|
||||||
|
msgid "Show when the editor opens"
|
||||||
|
msgstr "Pokazuj po otwarciu edytora"
|
||||||
|
|
||||||
|
msgid "L, LMB, LMB..."
|
||||||
|
msgstr "L, LPM, LPM..."
|
||||||
|
|
||||||
|
msgid "Lay track: each click lays a piece and goes on from its end"
|
||||||
|
msgstr "Układanie toru: każdy klik kładzie odcinek i ciągnie tor dalej z jego końca"
|
||||||
|
|
||||||
|
msgid "Lead a track out of it; onto another free end: join the two"
|
||||||
|
msgstr "Wyprowadza z niego tor; na inny wolny koniec: łączy oba"
|
||||||
|
|
||||||
|
msgid "Laying: radius"
|
||||||
|
msgstr "Układanie: promień"
|
||||||
|
|
||||||
|
msgid "Laying: arc then straight, straight then arc, arc, straight; at a free end: another way to join"
|
||||||
|
msgstr "Układanie: łuk i prosta, prosta i łuk, łuk, prosta; na wolnym końcu: inny sposób połączenia"
|
||||||
|
|
||||||
|
msgid "0-9 while laying"
|
||||||
|
msgstr "0-9 w trakcie układania"
|
||||||
|
|
||||||
|
msgid "Type the length (or the radius) of the next piece, Enter lays it"
|
||||||
|
msgstr "Wpisz długość (lub promień) następnego odcinka, Enter go kładzie"
|
||||||
|
|||||||
Reference in New Issue
Block a user