From 16c90eb6742be3b57c9e438c913dc6152b0ee318 Mon Sep 17 00:00:00 2001 From: maj00r Date: Mon, 12 Oct 2026 02:21:29 +0200 Subject: [PATCH] feat(editor): Straight and Curve are one Plan tool (G, also C) right after Lay track, a straight opens with its grips, a curve or a line with its vertices; digits no longer type a length while extending from a free end; the scenery wizard chooses realistic or fictional, a realistic one gets //$g and //$o and opens with the orthophoto in the top view, a fictional one only the top view with the grid; the orthophoto settings are kept in the scenery as //$o (on, year, opacity, radius, height, drape, lift, hires, scene, origin) and survive the new formats; self-test command mapstate --- application/editormode.cpp | 22 ++++++++++-- application/editormode.h | 8 +++-- application/editormodeselftest.cpp | 7 ++++ application/editormodetrack.cpp | 57 +++++++++++++++++++----------- application/editormodetrackux.cpp | 41 ++------------------- application/editormodeviewport.cpp | 11 +++--- editor/editorOrthophoto.cpp | 51 ++++++++++++++++++++++++++ editor/editorOrthophoto.hpp | 2 ++ lang/editor_pl.po | 53 +++++++++++++++++++++------ launcher/scenery_wizard.cpp | 39 +++++++++++++++++--- launcher/scenery_wizard.h | 1 + scene/scenelayers.cpp | 2 +- 12 files changed, 209 insertions(+), 85 deletions(-) diff --git a/application/editormode.cpp b/application/editormode.cpp index 728c2c59..334485dd 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -2197,6 +2197,14 @@ void editor_mode::load_orthophoto_settings() config.north = m_georeference_origin.x; config.east = m_georeference_origin.y; } + auto enabled{m_orthophoto.enabled()}; + m_orthophoto_mark.clear(); + if (auto const marked{scene::Layers.empty() ? std::vector{} : scene::Layers.marked(scene::layer_handle{1}, "//$o")}; false == marked.empty() && editor_orthophoto::read_mark(marked.front(), config, enabled)) + { + m_orthophoto_mark = marked.front(); + m_orthophoto.enabled(enabled); + WriteLog(format("Editor: the map settings of the scenery, orthophoto %s", enabled ? "on" : "off")); + } m_orthophoto.settings(config); m_orthophoto_origin_edit = {config.north, config.east}; } @@ -2934,6 +2942,11 @@ bool editor_mode::save() m_saved_camera = std::make_pair(glm::dvec3{Camera.Pos}, glm::vec3{Camera.Angle}); scene::Layers.mark(scene::layer_handle{1}, "//$c", {format("%.3f %.3f %.3f %.5f %.5f", Camera.Pos.x, Camera.Pos.y, Camera.Pos.z, Camera.Angle.x, Camera.Angle.y)}); } + if (auto const map{editor_orthophoto::mark(m_orthophoto.settings(), m_orthophoto.enabled(), m_orthophoto.settings().north != 0.0 || m_orthophoto.settings().east != 0.0)}; false == m_orthophoto_scenery.empty() && map != m_orthophoto_mark && (m_orthophoto.enabled() || false == m_orthophoto_mark.empty())) + { + m_orthophoto_mark = map; + scene::Layers.mark(scene::layer_handle{1}, "//$o", {map}); + } auto const terrainadded{false == rootstatements.empty()}; auto const controls{turntable_controls(rootstatements)}; std::vector trailing; @@ -4707,7 +4720,7 @@ void editor_mode::render_shortcuts_window() {"Tracks", {{"Esc", "Select tool; cancels what's going on first"}, {"L / T / U", "Lay track / switch / turntable"}, - {"G / C", "Straight / curve"}, + {"G (C)", "Plan: a straight, its ends and the middle; a curve, its vertex and radius"}, {"H / B", "Signals / objects along the track"}, {"P / V / J / I", "Profile / speed / joints / infrastructure"}, {"Ctrl+F", "Find a track by its name"}, @@ -5236,10 +5249,15 @@ void editor_mode::enter() { std::vector 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.Pos = glm::dvec3{0.0, (found.front() != 0 ? ground : 0.0) + 60.0, 0.0}; Camera.Angle = glm::vec3(glm::radians(-45.0f), 0.0f, 0.0f); Camera.m_owner = nullptr; FreeFlyModeFlag = true; + if (false == Global.EditorOrtho) + { + Global.EditorOrthoExtent = 150.0f; + toggle_ortho(); + } Global.pCamera = Camera; choose_work_area(work_area::tracks); WriteLog("Editor: camera over the origin of the empty scenery"); diff --git a/application/editormode.h b/application/editormode.h index 4a6dc906..88137c31 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -521,6 +521,7 @@ class editor_mode : public application_mode, private editor_track::observer void save_orthophoto_settings(); editor_orthophoto m_orthophoto; std::string m_orthophoto_scenery; // scenery whose origin is loaded + std::string m_orthophoto_mark; glm::dvec2 m_orthophoto_origin_edit{0.0}; // origin being typed in (northing, easting); applied when editing ends // hierarchy management @@ -1206,7 +1207,9 @@ class editor_mode : public application_mode, private editor_track::observer track_tab tab; char const *tooltip; }; - static std::array const &track_modes(); + static std::array const &track_modes(); + bool track_plan_tab() const { return m_track_tab == track_tab::straights || m_track_tab == track_tab::route; } + track_tab plan_tab_for(TTrack const *Track) const; // the objects along the track: a tab for each tool int m_lineside_tab{0}; void render_lineside_ui(); @@ -1217,7 +1220,7 @@ class editor_mode : public application_mode, private editor_track::observer // the track tools in the tool options window, and the selected path in the inspector void render_track_tool_options(); void render_track_selection(); - void show_track_tab(track_tab const Tab); + void show_track_tab(track_tab const Wanted); bool track_analysis_tab() const { return m_track_tab == track_tab::profile || m_track_tab == track_tab::speed || m_track_tab == track_tab::joints || m_track_tab == track_tab::infra; } bool track_shortcut(int const Key); bool track_busy() const; // something going on in the mode, which Esc drops before it leaves the mode @@ -1878,7 +1881,6 @@ class editor_mode : public application_mode, private editor_track::observer char const *typed_meaning() const; std::vector typed_values() const; bool typed_key(int const Key); - void typed_extend(); glm::dvec3 typed_lay(glm::dvec3 const &Mouse) const; void typed_turn(); bool m_route_tab{true}; diff --git a/application/editormodeselftest.cpp b/application/editormodeselftest.cpp index fef32cf6..5cb4eb50 100644 --- a/application/editormodeselftest.cpp +++ b/application/editormodeselftest.cpp @@ -149,6 +149,12 @@ editor_mode::selftest_result editor_mode::selftest_scene(std::string const &comm save(); return selftest_result::handled; } + if (command == "mapstate") + { + auto const marked{scene::Layers.empty() ? std::vector{} : scene::Layers.marked(scene::layer_handle{1}, "//$o")}; + WriteLog(format("SELFTEST mapstate orthophoto %d top %d extent %.0f mark %s", m_orthophoto.enabled() ? 1 : 0, Global.EditorOrtho ? 1 : 0, Global.EditorOrthoExtent, marked.empty() ? "-" : marked.front().c_str())); + return selftest_result::handled; + } if (command == "trainset") { std::string name; @@ -2426,6 +2432,7 @@ editor_mode::selftest_result editor_mode::selftest_terrain(std::string const &co // checkspans logs whether the text the scenery files hold at each node's place starts and ends it // spread logs the paths the spread from the track takes // newscenery the editor starts again with the wizard of a new scenery +// mapstate logs the orthophoto, the top view and the //$o line of the scenery // trainset [km/h] the trainset tool puts the vehicle in the middle of the track // vehicles logs each vehicle: its head, facing, and what its couplers hold // terrainmode the terrain field of work, with its texture browser diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index b79f2b3f..1fc12de7 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -259,12 +259,17 @@ void editor_mode::select_track(scene::basic_node *Node) return; m_track_window_open = true; m_track_mode_notice.clear(); + if (track_plan_tab() && plan_tab_for(track) != m_track_tab) + { + show_track_tab(plan_tab_for(track)); + return; + } // the mode stays as it is, the path is taken up by it if it can be switch (m_track_tab) { case track_tab::straights: - if (track->eType == tt_Switch || false == editor_track::is_straight(*track, m_straights.tolerance)) - m_track_mode_notice = STR_C("The selected path isn't straight: C edits it as a curve, Esc goes back to Select"); + if (track->eType == tt_Switch) + m_track_mode_notice = STR_C("Switches aren't a part of a line: T edits the switch, Esc goes back to Select"); break; case track_tab::route: if (std::find(m_route.chain.tracks.begin(), m_route.chain.tracks.end(), track) != m_route.chain.tracks.end()) @@ -522,16 +527,15 @@ void editor_mode::restore_track_snapshot(EditorSnapshot const &Snapshot, std::ve profile_restore(); } -std::array const &editor_mode::track_modes() +std::array const &editor_mode::track_modes() { - static std::array const modes{{ + static std::array const modes{{ {"Select", "Esc", track_tab::path, "LMB on a path selects it: its points, control vectors and parameters"}, {"Lay track", "L", track_tab::lay, "Lays new track through the clicked points, on the ground or from a free end of a track"}, + {"Plan", "G", track_tab::straights, "The plan of the line laid: LMB on a straight drags its ends or the middle, on a curve its vertex and radius. C works too"}, {"Switch", "T", track_tab::turnout, "Puts switches into the selected straight or curve, edits the geometry of the selected switch"}, {"Parallel", "N", track_tab::parallel, "A second track beside a straight: LMB on the straight, then the side and the spacing"}, {"Turntable", "U", track_tab::turntable, "Places a turntable, leads tracks out of it and fits the tracks around to it"}, - {"Straight", "G", track_tab::straights, "The whole straight through the selected path: drag its ends or the middle, break it, shift it"}, - {"Curve", "C", track_tab::route, "The line through the path, switch to switch: vertices with the radii, transitions and cant of the curves"}, {"Signals", "H", track_tab::signals, "Signals by the track, from the templates of the scenery, with the event the train reads them by"}, {"Objects", "B", track_tab::lineside, "Along the track: hectometre posts, fouling point markers, trainsets"}, {"Profile", "P", track_tab::profile, "Vertical profile (grade line) along the line"}, @@ -542,8 +546,9 @@ std::array const &editor_mode::track_modes() return modes; } -void editor_mode::show_track_tab(track_tab const Tab) +void editor_mode::show_track_tab(track_tab const Wanted) { + auto const Tab{Wanted == track_tab::straights || Wanted == track_tab::route ? plan_tab_for(selected_track()) : Wanted}; m_track_window_open = true; m_roadtool.window = false; if (Tab == m_track_tab) @@ -567,8 +572,8 @@ void editor_mode::show_track_tab(track_tab const Tab) arm_switch(); break; case track_tab::straights: - if (track != nullptr && (track->eType == tt_Switch || false == editor_track::is_straight(*track, m_straights.tolerance))) - m_track_mode_notice = STR_C("The selected path isn't straight: LMB on a straight"); + if (track != nullptr && track->eType == tt_Switch) + m_track_mode_notice = STR_C("Switches aren't a part of a line: LMB on a plain path"); break; case track_tab::route: if (track != nullptr && std::find(m_route.chain.tracks.begin(), m_route.chain.tracks.end(), track) == m_route.chain.tracks.end()) @@ -615,17 +620,28 @@ void editor_mode::arm_switch() bool editor_mode::track_shortcut(int const Key) { + auto const key{Key == GLFW_KEY_C ? GLFW_KEY_G : Key}; for (auto const &mode : track_modes()) { - if (mode.key[1] != '\0' || Key != GLFW_KEY_A + (mode.key[0] - 'A')) + if (mode.key[1] != '\0' || key != GLFW_KEY_A + (mode.key[0] - 'A')) continue; // the key of the mode on leaves it - show_track_tab(m_track_window_open && m_track_tab == mode.tab ? track_tab::path : mode.tab); + auto const on{m_track_tab == mode.tab || (mode.tab == track_tab::straights && track_plan_tab())}; + show_track_tab(m_track_window_open && on ? track_tab::path : mode.tab); return true; } return false; } +editor_mode::track_tab editor_mode::plan_tab_for(TTrack const *Track) const +{ + if (Track == nullptr) + return track_plan_tab() ? m_track_tab : track_tab::straights; + if (Track->eType == tt_Normal && editor_track::is_supported(*Track) && false == editor_track::is_straight(*Track, m_straights.tolerance)) + return track_tab::route; + return track_tab::straights; +} + bool editor_mode::track_busy() const { auto const &straights{m_straights}; @@ -647,13 +663,13 @@ std::string editor_mode::track_mode_name() const return STR_C("Switch: press and drag on the selected track"); case track_tab::straights: if (false == m_straights.detour.empty()) - return STR_C("Straight: shift around, Shift+click the points"); + return STR_C("Plan, straight: shift around, Shift+click the points"); if (m_straights.tool == 1) - return STR_C("Straight: break, LMB on the straight"); + return STR_C("Plan, straight: break, LMB on the straight"); if (m_straights.tool == 2) - return STR_C("Straight: S-curve, LMB on the straight"); - return STR_C("Straight: drag its ends or the middle"); - case track_tab::route: return STR_C("Curve: drag the vertices and the radius grips"); + return STR_C("Plan, straight: S-curve, LMB on the straight"); + return STR_C("Plan, straight: drag its ends or the middle"); + case track_tab::route: return STR_C("Plan, curve: drag the vertices and the radius grips"); case track_tab::profile: return STR_C("Vertical profile: edit the grade line in the profile window"); case track_tab::speed: return STR_C("Speed check: LMB on a row shows the path"); case track_tab::joints: return STR_C("Joints: LMB on a row shows the place"); @@ -3735,14 +3751,14 @@ std::vector editor_mode::track_key_hints(bool const All) hints = {{"Drag the diamond", "snaps parallel at 4.00 / 4.50 / 4.75 m"}, {"Esc", "cancel"}}; } else if (m_track_tab == track_tab::straights && m_straights.current.tracks.empty()) - hints = {{"LMB on a straight track", "selects the whole straight"}}; + hints = {{"LMB on a straight", "its ends and the middle to drag"}, {"LMB on a curve", "its vertex and radius to drag"}}; else if (m_track_tab == track_tab::straights) { hints = {{"Drag a square", "moves an end, the curves at it follow"}, {"Drag the diamond", "shifts sideways; close: snaps parallel at 4.00 / 4.50 / 4.75 m"}, {"Ctrl+drag", "breaks the straight"}, {"Shift+click x4", "shifts a piece around an obstacle"}, {"Alt+click", "adds another straight to move together"}}; gizmo = true; } else if (m_track_tab == track_tab::route && m_route.chain.tracks.empty()) - hints = {{"LMB on a curve", "loads it with the straights at its ends"}}; + hints = {{"LMB on a straight", "its ends and the middle to drag"}, {"LMB on a curve", "its vertex and radius to drag"}}; else if (m_track_tab == track_tab::route) hints = {{"Drag yellow", "moves a vertex, the curve follows"}, {"Drag green", "changes the radius"}, {"Apply", "writes the design into the tracks"}, {"Esc", "release the vertex"}}; else if (selected == nullptr) @@ -4070,8 +4086,7 @@ void editor_mode::update_build_tools() { if (pointing) m_extend.mouse = cursor_terrain(m_extend.point.y); - typed_extend(); - m_extend.snap = m_typed.empty() && m_extend.track != nullptr ? snap_free_end(m_extend.mouse, cursor, m_extend.track, m_extend.track->iCategoryFlag & 15, {m_extend.track}) : editor_track::snap_target{}; + m_extend.snap = m_extend.track != nullptr ? snap_free_end(m_extend.mouse, cursor, m_extend.track, m_extend.track->iCategoryFlag & 15, {m_extend.track}) : editor_track::snap_target{}; if (m_extend.snap.track == nullptr) m_extend.mouse.y = bed_height(m_extend.mouse, plan_of(m_extend.mouse - m_extend.point), m_extend.track); joining(m_extend.snap); @@ -4504,7 +4519,7 @@ std::vector editor_mode::join_pieces(TTrack const *From, editor_tr void editor_mode::finish_extend() { auto const &io{ImGui::GetIO()}; - if (glm::length(glm::vec2{io.MousePos.x, io.MousePos.y} - m_extend.pressed) < kDragPixels && m_typed.empty()) + if (glm::length(glm::vec2{io.MousePos.x, io.MousePos.y} - m_extend.pressed) < kDragPixels) { m_extend.active = false; if (m_lay.active && m_lay.points.empty() && m_extend.origin.track != nullptr) diff --git a/application/editormodetrackux.cpp b/application/editormodetrackux.cpp index 02cd097e..16ea91cd 100644 --- a/application/editormodetrackux.cpp +++ b/application/editormodetrackux.cpp @@ -376,8 +376,8 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods) intent.position = m_hover.point; switch (m_track_tab) { - 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::straights: + case track_tab::route: return make(kind::select, m_hover.track->eType != tt_Switch && editor_track::is_straight(*m_hover.track, m_straights.tolerance) ? "Click: the whole straight through this track" : "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: 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::lineside: return make(kind::select, "Click: the line the objects go along"); @@ -649,10 +649,8 @@ void editor_mode::render_track_context() ImGui::Separator(); if (ImGui::MenuItem(STR_C("Switch"), "T", false, normal || track->eType == tt_Switch)) show_track_tab(track_tab::turnout); - if (ImGui::MenuItem(STR_C("Whole straight"), "G", false, normal && editor_track::is_straight(*track, m_straights.tolerance))) + if (ImGui::MenuItem(STR_C("Plan"), "G", false, normal)) show_track_tab(track_tab::straights); - if (ImGui::MenuItem(STR_C("Curve"), "C", false, normal)) - show_track_tab(track_tab::route); if (ImGui::MenuItem(STR_C("Parallel track"), "L", false, normal)) show_track_tab(track_tab::lay); if (ImGui::MenuItem(STR_C("Place a vehicle here"))) @@ -758,8 +756,6 @@ void editor_mode::render_track_search() char const *editor_mode::typed_meaning() const { auto const &straights{m_straights}; - if (m_extend.active) - return m_track_layout == track_layout::straight ? "type the length" : m_track_layout == track_layout::arc ? "type the radius, a space, the length" : "type the radius"; if (straights.dragging) return straights.handle == 2 ? "type the shift, + to the right" : "type the length"; if (straights.tool == 1 && (straights.tool_mouse || straights.tool_dragging)) @@ -821,37 +817,6 @@ bool editor_mode::typed_key(int const Key) return true; } -void editor_mode::typed_extend() -{ - auto const values{typed_values()}; - if (values.empty()) - return; - auto &tool{m_extend}; - auto const &direction{tool.direction}; - if (m_track_layout != track_layout::straight && m_track_layout != track_layout::arc) - return; - if (m_track_layout == track_layout::straight) - { - auto const length{std::max(0.0, values[0])}; - tool.mouse = {tool.point.x + direction.x * length, tool.mouse.y, tool.point.z + direction.y * length}; - return; - } - auto const radius{std::abs(values[0])}; - if (radius < 1.0) - return; - glm::dvec2 const offset{tool.mouse.x - tool.point.x, tool.mouse.z - tool.point.z}; - double const side{geometry::cross(direction, offset) >= 0.0 ? 1.0 : -1.0}; - glm::dvec2 const point{tool.point.x, tool.point.z}; - glm::dvec2 const centre{point + glm::dvec2{-direction.y, direction.x} * (side * radius)}; - auto const radial{point - centre}; - auto angle{values.size() > 1 ? std::abs(values[1]) / radius : side * geometry::signed_angle(radial, glm::dvec2{tool.mouse.x, tool.mouse.z} - centre)}; - if (angle < 0.0) - angle += 2.0 * glm::pi(); - angle = std::clamp(angle, 1e-3, glm::pi()); - auto const end{centre + geometry::turned(radial, side * angle)}; - tool.mouse = {end.x, tool.mouse.y, end.y}; -} - glm::dvec3 editor_mode::typed_lay(glm::dvec3 const &Mouse) const { auto const values{typed_values()}; diff --git a/application/editormodeviewport.cpp b/application/editormodeviewport.cpp index d3d4aeb2..e828a01f 100644 --- a/application/editormodeviewport.cpp +++ b/application/editormodeviewport.cpp @@ -163,11 +163,12 @@ void editor_mode::work_area_tools(std::vector &Buttons) if (found == modes.end()) return; // a tool chosen again gives way to the select one - auto const chosen{m_track_tab == Tab && false == (Tab == track_tab::lineside && vehicle)}; + auto const chosen{(m_track_tab == Tab || (Tab == track_tab::straights && track_plan_tab())) && false == (Tab == track_tab::lineside && vehicle)}; Buttons.push_back({Picture, STR_C(found->label), found->key, STR_C(found->tooltip), chosen, [this, Tab, chosen]() { show_track_tab(chosen ? track_tab::path : Tab); }, Group}); }; add(track_tab::path, icon::select, false); add(track_tab::lay, icon::lay_track, false); + add(track_tab::straights, icon::curve, false); add(track_tab::turnout, icon::turnout, false); add(track_tab::parallel, icon::parallel, false); add(track_tab::turntable, icon::turntable, false); @@ -177,17 +178,15 @@ void editor_mode::work_area_tools(std::vector &Buttons) show_track_tab(vehicle ? track_tab::path : track_tab::lineside); m_vehicle.expand = false == vehicle; }}); - auto const advanced{m_track_tab == track_tab::straights || m_track_tab == track_tab::route || m_track_tab == track_tab::profile || m_track_tab == track_tab::speed || m_track_tab == track_tab::joints || m_track_tab == track_tab::infra || m_gauge.open}; + auto const advanced{m_track_tab == track_tab::profile || m_track_tab == track_tab::speed || m_track_tab == track_tab::joints || m_track_tab == track_tab::infra || m_gauge.open}; auto const more{EditorSettings.track_tools_more()}; - Buttons.push_back({icon::more, more ? STR_C("Less") : STR_C("More"), nullptr, STR_C("The tools that correct a line already laid: straight, curve, profile, speed, joints, infrastructure, structure gauge"), more, [more]() { + Buttons.push_back({icon::more, more ? STR_C("Less") : STR_C("More"), nullptr, STR_C("The checks of a line laid: profile, speed, joints, infrastructure, structure gauge"), more, [more]() { EditorSettings.track_tools_more(false == more); EditorSettings.save(); }, true}); if (false == more && false == advanced) break; - add(track_tab::straights, icon::straight, true); - add(track_tab::route, icon::curve, false); - add(track_tab::profile, icon::profile, false); + add(track_tab::profile, icon::profile, true); add(track_tab::speed, icon::speed, false); add(track_tab::joints, icon::joints, false); add(track_tab::infra, icon::infra, false); diff --git a/editor/editorOrthophoto.cpp b/editor/editorOrthophoto.cpp index f7646e29..8e606d74 100644 --- a/editor/editorOrthophoto.cpp +++ b/editor/editorOrthophoto.cpp @@ -677,6 +677,57 @@ bool editor_orthophoto::owns(gfx::geometry_handle const &Geometry) return Geometry.bank != 0 && std::find(scene_banks.begin(), scene_banks.end(), Geometry.bank) != scene_banks.end(); } +std::string editor_orthophoto::mark(config const &Config, bool const Enabled, bool const Origin) +{ + char text[256]; + std::snprintf(text, sizeof(text), "on %d year %d opacity %.2f radius %d height %.2f drape %d lift %.2f hires %d scene %d", Enabled ? 1 : 0, Config.year, Config.opacity, Config.radius, Config.height, Config.drape ? 1 : 0, Config.lift, Config.hires ? 1 : 0, Config.in_scene ? 1 : 0); + std::string result{text}; + if (Origin) + { + std::snprintf(text, sizeof(text), " origin %.2f %.2f", Config.north, Config.east); + result += text; + } + return result; +} + +bool editor_orthophoto::read_mark(std::string const &Text, config &Config, bool &Enabled) +{ + std::istringstream words{Text}; + std::string key; + auto found{false}; + while (words >> key) + { + if (key == "on") + words >> Enabled; + else if (key == "year") + words >> Config.year; + else if (key == "opacity") + words >> Config.opacity; + else if (key == "radius") + words >> Config.radius; + else if (key == "height") + words >> Config.height; + else if (key == "drape") + words >> Config.drape; + else if (key == "lift") + words >> Config.lift; + else if (key == "hires") + words >> Config.hires; + else if (key == "scene") + words >> Config.in_scene; + else if (key == "origin") + words >> Config.north >> Config.east; + else + continue; + if (words.fail()) + return found; + found = true; + } + Config.radius = std::clamp(Config.radius, 0, max_radius); + Config.opacity = std::clamp(Config.opacity, 0.0f, 1.0f); + return found; +} + void editor_orthophoto::enabled(bool State) { if (State == m_enabled) diff --git a/editor/editorOrthophoto.hpp b/editor/editorOrthophoto.hpp index 8d7d942f..1a808d04 100644 --- a/editor/editorOrthophoto.hpp +++ b/editor/editorOrthophoto.hpp @@ -93,6 +93,8 @@ class editor_orthophoto // disabling drops the queue and returns the gpu memory of the resident tiles void enabled(bool State); config const &settings() const { return m_config; } + static std::string mark(config const &Config, bool Enabled, bool Origin); + static bool read_mark(std::string const &Text, config &Config, bool &Enabled); // changes of year / resolution invalidate resident tiles, the rest applies immediately void settings(config const &Config); void ground_source(ground_query Query) { m_ground = std::move(Query); } diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 1e6321d5..0d445a2a 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -38,26 +38,26 @@ msgstr "Rozjazd: przeciągnij, aby ustawić kierunek i stronę" msgid "Switch: press and drag on the selected track" msgstr "Rozjazd: wciśnij i przeciągnij na wybranym torze" -msgid "Straight: shift around, Shift+click the points" -msgstr "Prosta: objazd, Shift+klik w punkty" +msgid "Plan, straight: shift around, Shift+click the points" +msgstr "Plan, prosta: objazd, Shift+klik w punkty" msgid "New path from the free end" msgstr "Nowy odcinek z wolnego końca" -msgid "Straight: break, LMB on the straight" -msgstr "Prosta: załamanie, LPM na prostej" +msgid "Plan, straight: break, LMB on the straight" +msgstr "Plan, prosta: załamanie, LPM na prostej" -msgid "Straight: S-curve, LMB on the straight" -msgstr "Prosta: przesunięcie (esowanie), LPM na prostej" +msgid "Plan, straight: S-curve, LMB on the straight" +msgstr "Plan, prosta: przesunięcie (esowanie), LPM na prostej" -msgid "Straight: drag its ends or the middle" -msgstr "Prosta: przeciągaj końce lub środek" +msgid "Plan, straight: drag its ends or the middle" +msgstr "Plan, prosta: przeciągaj końce lub środek" msgid "Select: LMB on a path" msgstr "Wybór: LPM na odcinku" -msgid "Curve: drag the vertices and the radius grips" -msgstr "Łuk: przeciągaj wierzchołki i uchwyty promienia" +msgid "Plan, curve: drag the vertices and the radius grips" +msgstr "Plan, łuk: przeciągaj wierzchołki i uchwyty promienia" msgid "Switch: move and turn it with the gizmo" msgstr "Rozjazd: przesuwaj i obracaj gizmem" @@ -5727,3 +5727,36 @@ msgstr "Nie trafi do scenerii; pojazdy zostają do ponownego wczytania scenerii" msgid "%d trainset(s) written to the scenery" msgstr "Zapisano %d skład(ów) do scenerii" + +msgid "Plan" +msgstr "Plan" + +msgid "The plan of the line laid: LMB on a straight drags its ends or the middle, on a curve its vertex and radius. C works too" +msgstr "Plan ułożonej linii: LPM na prostej – ciągniesz jej końce lub środek, na łuku – wierzchołek i promień. Działa też C" + +msgid "The checks of a line laid: profile, speed, joints, infrastructure, structure gauge" +msgstr "Kontrole ułożonej linii: profil, prędkość, styki, infrastruktura, skrajnia" + +msgid "its ends and the middle to drag" +msgstr "jej końce i środek do ciągnięcia" + +msgid "its vertex and radius to drag" +msgstr "jego wierzchołek i promień do ciągnięcia" + +msgid "G (C)" +msgstr "G (C)" + +msgid "Plan: a straight, its ends and the middle; a curve, its vertex and radius" +msgstr "Plan: prosta – jej końce i środek; łuk – wierzchołek i promień" + +msgid "Realistic" +msgstr "Realistyczna" + +msgid "A real place: the centre is picked on the map, the editor opens with the orthophoto under it, seen from above" +msgstr "Prawdziwe miejsce: środek wybierasz na mapie, edytor otwiera się z ortofotomapą pod spodem, w widoku z góry" + +msgid "Fictional" +msgstr "Fikcyjna" + +msgid "No place on the map, no orthophoto: an empty plane seen from above" +msgstr "Bez miejsca na mapie i bez ortofotomapy: pusta płaszczyzna w widoku z góry" diff --git a/launcher/scenery_wizard.cpp b/launcher/scenery_wizard.cpp index 01485203..59a5de87 100644 --- a/launcher/scenery_wizard.cpp +++ b/launcher/scenery_wizard.cpp @@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/. #include "application/application.h" #include "editor/editorFormat.hpp" #include "editor/editorOrthophoto.hpp" +#include "editor/editorSettings.hpp" #include "utilities/Globals.h" #include "utilities/Logs.h" #include "utilities/translation.h" @@ -270,7 +271,18 @@ void ui::scenerywizard_panel::render_form() { ImGui::TextUnformatted(STR_C("New scenery")); ImGui::Separator(); - ImGui::TextWrapped("%s", STR_C("Find the place on the map: the wheel zooms, dragging moves the map. A click sets the centre of the scenery, its point 0 0 0.")); + if (ImGui::RadioButton(STR_C("Realistic"), m_realistic)) + m_realistic = true; + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", STR_C("A real place: the centre is picked on the map, the editor opens with the orthophoto under it, seen from above")); + ImGui::SameLine(); + if (ImGui::RadioButton(STR_C("Fictional"), false == m_realistic)) + m_realistic = false; + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", STR_C("No place on the map, no orthophoto: an empty plane seen from above")); + ImGui::Spacing(); + if (m_realistic) + ImGui::TextWrapped("%s", STR_C("Find the place on the map: the wheel zooms, dragging moves the map. A click sets the centre of the scenery, its point 0 0 0.")); ImGui::Spacing(); ImGui::SetNextItemWidth(-1.f); @@ -293,6 +305,7 @@ void ui::scenerywizard_panel::render_form() ImGui::InputTextWithHint("##title", STR_C("title, written in the file"), m_title, sizeof(m_title)); ImGui::Spacing(); + ImGui::BeginDisabled(false == m_realistic); ImGui::TextUnformatted(STR_C("Centre of the scenery, PUWG 1992")); double east{m_point.x / 1000.0}; double north{m_point.y / 1000.0}; @@ -335,11 +348,13 @@ void ui::scenerywizard_panel::render_form() } ImGui::Spacing(); ImGui::TextWrapped("%s", STR_C("The scenery keeps the centre as its geographic reference (//$g PUWG1992): the orthophoto of the editor lies under it, in place.")); + ImGui::EndDisabled(); ImGui::Spacing(); - auto const ready{named && false == exists && m_picked}; + auto const placed{m_picked || false == m_realistic}; + auto const ready{named && false == exists && placed}; if (false == ready) - ImGui::TextDisabled("%s", m_picked ? STR_C("Give the file a name") : STR_C("Click the centre on the map")); + ImGui::TextDisabled("%s", placed ? STR_C("Give the file a name") : STR_C("Click the centre on the map")); if (ImGui::Button(STR_C("Create and open in the editor"), ImVec2(-1.f, 0.f)) && ready) create_scenery(); if (false == m_status.empty()) @@ -366,7 +381,23 @@ bool ui::scenerywizard_panel::create_scenery() std::strftime(date, sizeof(date), "%Y-%m-%d", std::localtime(&now)); char reference[96]; std::snprintf(reference, sizeof(reference), "//$g PUWG1992 %.3f %.3f", m_point.x / 1000.0, m_point.y / 1000.0); - output << reference << "\r\n"; + if (m_realistic) + { + auto const &stored{EditorSettings.orthophoto()}; + editor_orthophoto::config map; + map.radius = stored.radius; + map.height = stored.height; + map.opacity = stored.opacity; + map.year = stored.year; + map.hires = stored.hires; + map.drape = stored.drape; + map.lift = stored.lift; + map.in_scene = stored.in_scene; + output << reference << "\r\n"; + output << "//$o " << editor_orthophoto::mark(map, true, false) << "\r\n"; + } + else + std::snprintf(reference, sizeof(reference), "fictional"); if (m_title[0] != '\0') output << "// " << m_title << "\r\n"; output << "// created in the editor " << date << "\r\n\r\n"; diff --git a/launcher/scenery_wizard.h b/launcher/scenery_wizard.h index fb120c31..cd22dff7 100644 --- a/launcher/scenery_wizard.h +++ b/launcher/scenery_wizard.h @@ -60,6 +60,7 @@ class scenerywizard_panel : public ui_panel std::string m_map_error; bool m_picked{false}; + bool m_realistic{true}; glm::dvec2 m_point{0.0}; char m_filename[64]{}; char m_title[128]{}; diff --git a/scene/scenelayers.cpp b/scene/scenelayers.cpp index cda7972b..01d41014 100644 --- a/scene/scenelayers.cpp +++ b/scene/scenelayers.cpp @@ -837,7 +837,7 @@ bool node_layers::pending() const namespace { // marks of the lines the editor keeps track of -std::array const editormarks{"//$p", "//$h", "//$r", "//$b", "//$c"}; +std::array const editormarks{"//$p", "//$h", "//$r", "//$b", "//$c", "//$o"}; } // namespace void node_layers::scan(layer_handle const Layer)