mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-29 01:07:28 +01:00
Sieć trakcyjna: przęsła wg typów sieci, wysięgniki z katalogu, bramki, kotwienia i edytor sieci
Sam kod exe z gałęzi siec-trakcyjna (bez testów, notatek i danych z tests/catenary). Dane (data/traction_*.txt) leżą poza repozytorium. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Tqn7T8D1Gx3ptKtZgNtX5
This commit is contained in:
@@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/Timer.h"
|
||||
#include "world/Event.h"
|
||||
#include "world/TractionPower.h"
|
||||
#include "world/catenary_span.h"
|
||||
#include "vehicle/Camera.h"
|
||||
#include "world/mtable.h"
|
||||
#include "vehicle/Train.h"
|
||||
@@ -1540,6 +1541,10 @@ debug_panel::render_section_settings() const {
|
||||
if( ImGui::SliderFloat( ( to_string( std::abs( Global.gfx_shadow_angle_min ), 2 ) + "###shadowanglecutoff" ).c_str(), &Global.gfx_shadow_angle_min, -1.0, -0.2f, "Shadow angle cutoff" ) ) {
|
||||
Global.gfx_shadow_angle_min = quantize( Global.gfx_shadow_angle_min, 0.05f );
|
||||
}
|
||||
// sieć trakcyjna: zasięg rysowania przewodów, lin i uchwytów jako brył; 0 wyłącza bryły
|
||||
if( ImGui::SliderFloat( ( to_string( CatenarySettings.solid_range, 0 ) + " m###catenarysolidrange" ).c_str(), &CatenarySettings.solid_range, 0.0f, 500.0f, "3D overhead wires range" ) ) {
|
||||
CatenarySettings.solid_range = quantize( CatenarySettings.solid_range, 10.0f );
|
||||
}
|
||||
if( DebugModeFlag ) {
|
||||
// sky sliders
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@ extern char **environ;
|
||||
#include "editor/editorIncludeInfo.hpp"
|
||||
#include "editor/editorGroundMesh.hpp"
|
||||
#include "editor/editorFormat.hpp"
|
||||
#include "world/catenary_scene.h"
|
||||
#include "editor/editorGeometry.hpp"
|
||||
#include "editor/editorIcons.hpp"
|
||||
#include "utilities/translation.h"
|
||||
@@ -1264,6 +1265,7 @@ void editor_mode::redo_one()
|
||||
|
||||
bool editor_mode::update()
|
||||
{
|
||||
// the catenary doesn't need the far tracks drawn (50 km of them cost a lot in a big scenery)
|
||||
Global.editor_tracks = (current_work_area() == work_area::tracks);
|
||||
selftest_step();
|
||||
if (m_vehicle.leave)
|
||||
@@ -1420,6 +1422,11 @@ bool editor_mode::update()
|
||||
signal_move_update();
|
||||
draw_signal_overlay();
|
||||
}
|
||||
if (m_track_tab == track_tab::catenary)
|
||||
{
|
||||
catenary_drag_update();
|
||||
draw_catenary_overlay();
|
||||
}
|
||||
draw_parallel_preview();
|
||||
if (m_track_tab == track_tab::lineside)
|
||||
{
|
||||
@@ -2901,6 +2908,23 @@ bool editor_mode::save()
|
||||
if (m_profile.changed)
|
||||
profile_store();
|
||||
infra_store();
|
||||
// the catenary (cantilevers on the poles) lives in files of its own; a file made in the editor needs the directive
|
||||
std::vector<std::string> catenarynew;
|
||||
if (catenary_scene_changed())
|
||||
{
|
||||
std::string message;
|
||||
if (false == catenary_scene_save(message))
|
||||
{
|
||||
ui()->set_status(format(STR_C("The catenary couldn't be saved: %s"), message.c_str()), true);
|
||||
return false;
|
||||
}
|
||||
WriteLog("Editor: catenary written: " + message, logtype::generic);
|
||||
}
|
||||
for (auto const &file : catenary_scene_new_files())
|
||||
{
|
||||
rootstatements.emplace_back("catenary " + file + " endcatenary");
|
||||
catenarynew.push_back(file);
|
||||
}
|
||||
if (false == m_saved_camera.has_value() || glm::distance(m_saved_camera->first, glm::dvec3{Camera.Pos}) > 0.5 || glm::distance(m_saved_camera->second, glm::vec3{Camera.Angle}) > 0.01f)
|
||||
{
|
||||
m_saved_camera = std::make_pair(glm::dvec3{Camera.Pos}, glm::vec3{Camera.Angle});
|
||||
@@ -2926,6 +2950,9 @@ bool editor_mode::save()
|
||||
{
|
||||
scene::Layers.terrain_directive(true);
|
||||
}
|
||||
if (result.success)
|
||||
for (auto const &file : catenarynew)
|
||||
catenary_scene_file_included(file);
|
||||
ui()->set_status(result.message, false == result.success);
|
||||
WriteLog("Editor: " + result.message, logtype::generic);
|
||||
return result.success;
|
||||
@@ -3555,6 +3582,7 @@ void editor_mode::render_environment_window()
|
||||
{
|
||||
Global.AirTemperature = std::clamp(temperature, -35.0f, 40.0f);
|
||||
simulation::Environment.compute_weather();
|
||||
catenary_scene_temperature(); // ciężary kotwień idą za temperaturą
|
||||
}
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
|
||||
ImGui::TextWrapped("%s", STR_C("Seen in the editor only; the scenery keeps its own time and weather"));
|
||||
@@ -4395,7 +4423,7 @@ editor_mode::work_area editor_mode::current_work_area() const
|
||||
if (m_terrain_open)
|
||||
return work_area::terrain;
|
||||
if (m_track_window_open)
|
||||
return work_area::tracks;
|
||||
return m_track_tab == track_tab::catenary ? work_area::catenary : work_area::tracks;
|
||||
if (m_roadtool.window)
|
||||
return work_area::roads;
|
||||
return work_area::surroundings;
|
||||
@@ -4411,7 +4439,11 @@ void editor_mode::choose_work_area(work_area const Area)
|
||||
break;
|
||||
case work_area::tracks:
|
||||
terrain_workspace(false);
|
||||
show_track_tab(m_track_tab);
|
||||
show_track_tab(m_track_tab == track_tab::catenary ? track_tab::path : m_track_tab);
|
||||
break;
|
||||
case work_area::catenary:
|
||||
terrain_workspace(false);
|
||||
show_track_tab(track_tab::catenary);
|
||||
break;
|
||||
case work_area::roads:
|
||||
m_track_window_open = false;
|
||||
@@ -4440,8 +4472,9 @@ void editor_mode::render_workspaces()
|
||||
{STR_C("Tracks"), work_area::tracks, editor_icons::icon::work_tracks, STR_C("Tracks and switches, signals, objects along the track, checks of the line")},
|
||||
{STR_C("Roads"), work_area::roads, editor_icons::icon::work_roads, STR_C("Roads and junctions, level crossings, the points where the traffic comes and goes")},
|
||||
{STR_C("Terrain"), work_area::terrain, editor_icons::icon::work_terrain, STR_C("Heightmap terrain: chunks, sculpting, painting, water, orthophoto")},
|
||||
{STR_C("Catenary"), work_area::catenary, editor_icons::icon::work_catenary, STR_C("The overhead catenary: poles with cantilevers, gantries, the wires of the chains")},
|
||||
};
|
||||
char const *const keys[] = {"F2", "F3", "F4", "F5"};
|
||||
char const *const keys[] = {"F2", "F3", "F4", "F5", "F6"};
|
||||
auto const current{current_work_area()};
|
||||
auto const &style{ImGui::GetStyle()};
|
||||
auto *list{ImGui::GetWindowDrawList()};
|
||||
@@ -4581,7 +4614,7 @@ void editor_mode::render_shortcuts_window()
|
||||
{"Ctrl+Shift+F11", "Export scenery dump"},
|
||||
{"F11", "Leave the editor"},
|
||||
{"F10", "Quit"}}},
|
||||
{"Fields of work", {{"F2", "Surroundings"}, {"F3", "Tracks"}, {"F4", "Roads"}, {"F5", "Terrain"}}},
|
||||
{"Fields of work", {{"F2", "Surroundings"}, {"F3", "Tracks"}, {"F4", "Roads"}, {"F5", "Terrain"}, {"F6", "Catenary"}}},
|
||||
{"Camera",
|
||||
{{"RMB held, mouse", "Look around"},
|
||||
{"RMB held, W S A D", "Fly forwards, back, left, right (arrows in the legacy scheme)"},
|
||||
@@ -5198,6 +5231,8 @@ void editor_mode::delete_selected()
|
||||
// what's selected: a road piece or point, a signal, an include of a scenery template, a model, tracks
|
||||
if (road_delete())
|
||||
return;
|
||||
if (m_track_tab == track_tab::catenary && ui()->mode() == nodebank_panel::TRACK && catenary_delete_selected())
|
||||
return;
|
||||
if (m_instance != 0 && signal_delete(m_instance))
|
||||
return;
|
||||
if (m_instance != 0)
|
||||
@@ -5265,6 +5300,10 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
if (ui()->mode() == nodebank_panel::TRACK && is_press(Action) && (Mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)) == 0 && typed_key(Key))
|
||||
return;
|
||||
|
||||
// the catenary tool may have keys of its own
|
||||
if (ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::catenary && catenary_on_key(Key, Action, Mods))
|
||||
return;
|
||||
|
||||
// gizmo transform shortcuts (Q/W/E/R) — only when the camera isn't being flown (RMB up).
|
||||
// handled before the camera keyboard step because Q/W/E are also the fly-mode movement keys,
|
||||
// which would otherwise consume them.
|
||||
@@ -5288,6 +5327,7 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
case GLFW_KEY_F3: choose_work_area(work_area::tracks); break;
|
||||
case GLFW_KEY_F4: choose_work_area(work_area::roads); break;
|
||||
case GLFW_KEY_F5: choose_work_area(work_area::terrain); break;
|
||||
case GLFW_KEY_F6: choose_work_area(work_area::catenary); break;
|
||||
// the edit modes in the order of the toolbar; in the track mode the digits typed as a value were taken already
|
||||
case GLFW_KEY_1: choose_edit_mode(nodebank_panel::MODIFY); break;
|
||||
case GLFW_KEY_2: choose_edit_mode(nodebank_panel::ADD); break;
|
||||
@@ -5355,6 +5395,9 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
return;
|
||||
if (Global.ctrlState && Key == GLFW_KEY_Z && is_press(Action))
|
||||
{
|
||||
// in the catenary tool its own changes are taken back first
|
||||
if (ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::catenary && catenary_undo())
|
||||
return;
|
||||
undo_last();
|
||||
return;
|
||||
}
|
||||
@@ -5690,6 +5733,8 @@ void editor_mode::on_mouse_button(int const Button, int const Action, int const
|
||||
turntable_finish_placement();
|
||||
if (m_signal.placing || m_signal.moving)
|
||||
signal_release();
|
||||
if (catenary_dragging())
|
||||
catenary_release();
|
||||
}
|
||||
|
||||
m_dragging = false;
|
||||
|
||||
@@ -48,6 +48,8 @@ struct vehicle_desc;
|
||||
struct skin_set;
|
||||
}
|
||||
|
||||
struct catenary_editor; // application/editormodecatenary.h
|
||||
|
||||
class editor_mode : public application_mode, private editor_track::observer
|
||||
{
|
||||
|
||||
@@ -606,7 +608,8 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
surroundings,
|
||||
tracks,
|
||||
roads,
|
||||
terrain
|
||||
terrain,
|
||||
catenary // the catenary tool of the tracks, as a field of work of its own
|
||||
};
|
||||
work_area current_work_area() const;
|
||||
void choose_work_area(work_area const Area);
|
||||
@@ -1013,7 +1016,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
void update_build_tools();
|
||||
void draw_build_overlay() const;
|
||||
// modes of the track editor, one at a time: path is the plain selection
|
||||
enum class track_tab { straights, route, path, turnout, profile, speed, joints, infra, lay, lineside, turntable, signals };
|
||||
enum class track_tab { straights, route, path, turnout, profile, speed, joints, infra, lay, lineside, turntable, signals, catenary };
|
||||
struct track_mode
|
||||
{
|
||||
char const *label;
|
||||
@@ -1021,7 +1024,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
track_tab tab;
|
||||
char const *tooltip;
|
||||
};
|
||||
static std::array<track_mode, 12> const &track_modes();
|
||||
static std::array<track_mode, 13> const &track_modes();
|
||||
// the objects along the track: a tab for each tool
|
||||
int m_lineside_tab{0};
|
||||
void render_lineside_ui();
|
||||
@@ -1078,7 +1081,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
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 };
|
||||
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, catenary };
|
||||
kind what{kind::none};
|
||||
TTrack *track{nullptr};
|
||||
int path{0};
|
||||
@@ -1087,6 +1090,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
glm::dvec3 position{0.0};
|
||||
editor_track::snap_target snap;
|
||||
std::string action;
|
||||
int detail{0}; // what the tool of the intent means by it (catenary: what was hit)
|
||||
};
|
||||
track_intent m_intent;
|
||||
track_intent track_intent_at(int const Mods);
|
||||
@@ -1489,6 +1493,28 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
std::string signal_intent_label(signal_template const &Template, signal_spot const &Spot) const;
|
||||
std::string signal_variant(signal_template const &Template, signal_spot const &Spot) const;
|
||||
|
||||
// catenary (sieć trakcyjna): the whole tool, its state and its workings are in application/editormodecatenary.h/.cpp;
|
||||
// here only the fixed hooks the rest of the editor calls, so changes of the tool rebuild only its own file
|
||||
friend struct catenary_editor;
|
||||
std::shared_ptr<catenary_editor> m_catenary_editor;
|
||||
catenary_editor &catenary_tool();
|
||||
void catenary_scan();
|
||||
bool catenary_intent(track_intent &Intent); // in the catenary tab: what a click would do; false: nothing
|
||||
void catenary_press(track_intent const &Intent);
|
||||
void catenary_release();
|
||||
bool catenary_dragging() const;
|
||||
void catenary_drag_update();
|
||||
void draw_catenary_overlay() const;
|
||||
void render_catenary_ui();
|
||||
bool catenary_delete_selected();
|
||||
bool catenary_undo(); // false: nothing of its own to take back
|
||||
bool catenary_on_key(int const Key, int const Action, int const Mods); // true: the key was used by the tool
|
||||
std::string catenary_mode_name() const;
|
||||
void catenary_key_hints(std::vector<key_hint> &Hints) const;
|
||||
// the page of the catenary field of work: 0 poles, 1 gantries, 2 wires
|
||||
int catenary_page();
|
||||
void catenary_choose_page(int const Page);
|
||||
|
||||
// a model laid along the track: bent to follow it, or repeated along it
|
||||
struct sweep_tool
|
||||
{
|
||||
|
||||
3286
application/editormodecatenary.cpp
Normal file
3286
application/editormodecatenary.cpp
Normal file
File diff suppressed because it is too large
Load Diff
208
application/editormodecatenary.h
Normal file
208
application/editormodecatenary.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// The catenary tool of the editor (sieć trakcyjna): its state and workings. The editor (editormode.h) holds it behind a
|
||||
// pointer and calls it through a few fixed hooks, so a change here rebuilds only editormodecatenary.cpp, not the files
|
||||
// which include editormode.h. The tool is a friend of editor_mode and reaches the editor through `e`.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "application/editormode.h"
|
||||
#include "world/catenary_suspension.h"
|
||||
#include "world/catenary_cantilever.h"
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct catenary_editor
|
||||
{
|
||||
explicit catenary_editor(editor_mode &Editor) : e{Editor} {}
|
||||
editor_mode &e;
|
||||
using track_intent = editor_mode::track_intent;
|
||||
using key_hint = editor_mode::key_hint;
|
||||
// what a catenary intent (track_intent::kind::catenary) is about, in its detail
|
||||
enum class intent_detail { place, select, chain, gantry, mast };
|
||||
static bool is_intent(track_intent const &Intent, intent_detail const Detail)
|
||||
{
|
||||
return Intent.what == track_intent::kind::catenary && Intent.detail == static_cast<int>(Detail);
|
||||
}
|
||||
|
||||
// catenary: poles with cantilevers by the track, put where the user sees them (on the orthophoto), the cantilever card
|
||||
// chosen from the catalogue by the distance from the face of the pole; spans checked against the catalogue tables
|
||||
struct catenary_spot
|
||||
{
|
||||
TTrack *track{nullptr};
|
||||
int path{0};
|
||||
double parameter{0.0};
|
||||
glm::dvec3 axis{0.0}; // the point of the path, under the rail heads
|
||||
glm::dvec2 forward{0.0, 1.0};
|
||||
int side{1}; // the pole on the right (+1) or on the left (-1) of the direction of the path
|
||||
double radius{0.0}; // of the track there, 0 on a straight
|
||||
bool curve{false};
|
||||
bool toward{true}; // the wires are offset towards the pole
|
||||
double reach{0.0}; // A: from the wires to the face of the pole
|
||||
int card{0};
|
||||
std::string problem; // why there's no card, empty when there is one
|
||||
std::string family; // the family of the card in the described catalogue; empty without it
|
||||
bool execution_changed{false}; // the execution chosen in the panel has no card for this A, another one was taken
|
||||
bool switch_error{false}; // a pole of a group that doesn't stand by switches (concrete), standing by one
|
||||
catenary::suspension data;
|
||||
};
|
||||
struct catenary_change
|
||||
{
|
||||
int group{0}; // changes of one action are taken back together
|
||||
bool chain{false}; // a change of a chain, otherwise of a suspension
|
||||
std::size_t index{0};
|
||||
std::optional<catenary::suspension> before; // none: the suspension was added
|
||||
std::optional<catenary::chain> chain_before; // none: the chain was added
|
||||
bool removed{false}; // the suspension was removed
|
||||
bool gantry{false}; // a change of a gantry
|
||||
std::optional<catenary::gantry> gantry_before; // none: the gantry was added
|
||||
bool anchor{false}; // a change of an anchor
|
||||
std::optional<catenary::anchor> anchor_before; // none: the anchor was added
|
||||
};
|
||||
struct catenary_tool
|
||||
{
|
||||
std::vector<std::string> poles;
|
||||
std::vector<std::string> networks;
|
||||
int pole{0};
|
||||
int network{0};
|
||||
int zone{1};
|
||||
int execution{1};
|
||||
bool swinging{true};
|
||||
bool toward{true};
|
||||
bool alternate{true}; // on a straight the next one goes the other way
|
||||
int bend{0}; // 0: from the track, 1: straight, 2: curve
|
||||
float stagger{0.30f};
|
||||
float clearance{2.50f}; // from the axis of the track to the face of the pole
|
||||
float height{5.60f}; // of the contact wires over the rails
|
||||
float system_height{0.0f}; // hk: of the messenger over the contact wires; 0 = the card's
|
||||
bool insulators25{false};
|
||||
char file[128]{};
|
||||
int selected{-1};
|
||||
// chains: the poles placed one after another are joined by spans
|
||||
bool chaining{true};
|
||||
int chain{-1}; // the chain the next pole is added to
|
||||
int last{-1}; // the pole the next span starts at
|
||||
bool append{true}; // the next pole goes after the last one of the chain, otherwise before the first
|
||||
int chain_selected{-1}; // the chain shown in the panel
|
||||
int connect_from{-1}; // hanging the wires on from this suspension: the next poles clicked get the spans
|
||||
char power[64]{"none"};
|
||||
float voltage{3000.0f};
|
||||
int material{0}; // 0 cu, 1 al
|
||||
int state{0}; // 0 new, 1 worn, 2 tarnished (state 0, 2, 1 in the entry)
|
||||
std::map<std::size_t, catenary_spot> spots; // where the suspensions are by the track, by their numbers
|
||||
std::vector<catenary_change> undo;
|
||||
int group{0};
|
||||
catenary::cantilever_result probe;
|
||||
bool probed{false};
|
||||
bool probe_good{false};
|
||||
std::string status;
|
||||
bool scanned{false};
|
||||
// gantries: two masts and the beam between them, drops with cantilevers on the beam
|
||||
std::vector<std::string> masts;
|
||||
int mast_first{0};
|
||||
int mast_second{0};
|
||||
bool mast_second_own{false}; // the second mast was picked by the user: it no longer follows the first
|
||||
bool gantry_high{false};
|
||||
int gantry_side{1};
|
||||
bool gantry_placing{false}; // the next two clicks put the masts
|
||||
bool gantry_single{false}; // what's placed is a single beam element on one through mast: the second click sets its direction
|
||||
std::optional<glm::dvec3> gantry_first; // the first mast, waiting for the second
|
||||
std::optional<glm::dvec2> gantry_track; // the direction of the track by the first mast, for the beam square to it
|
||||
bool gantry_square{true}; // the beam goes square to the track
|
||||
bool gantry_snap{true}; // the first mast goes at gantry_face from the axis of the track under the cursor
|
||||
int shift_group{0}; // the undo group of the distance of a mast being dragged; 0: the next change opens one
|
||||
float gantry_face{2.50f}; // from the axis of the track to the face of the mast (towards the track)
|
||||
char gantry_skin[128]{}; // the replaceable texture of the masts, the beam and the drops
|
||||
int dragging{0}; // 1: the selected pole along the track, 2: the selected gantry along the track
|
||||
glm::vec2 pressed{0.f};
|
||||
glm::dvec3 drag_start{0.0}; // the point of the ground the drag started at
|
||||
std::vector<std::pair<std::size_t, catenary::gantry>> drag_group; // the spans of the dragged gantry as they were when the drag started
|
||||
int drag_undo{0};
|
||||
glm::dvec3 drag_anchor{0.0}; // the first mast of the dragged gantry where the drag started
|
||||
double drag_axis{0.0}; // its axis from the axis of the track then: the drag keeps it there ("first mast from the track") // the undo group of the drag, opened at its first move
|
||||
std::vector<std::pair<std::size_t, catenary::suspension>> drag_drops; // the drops of the gantry, as they were
|
||||
int gantry_selected{-1}; // the gantry the drops go to
|
||||
std::string drop_choice; // the drop for the next cantilevers on a gantry; empty: the shortest one which fits
|
||||
// the described catalogue (data/traction_catalog.txt): the group the user picks, the family and the card in it
|
||||
// (empty / 0: chosen by the track, the stagger and the distance A)
|
||||
std::string catalog_kind;
|
||||
std::string catalog_group;
|
||||
std::string catalog_family;
|
||||
int catalog_card{0};
|
||||
int page{0}; // the page of the catenary field of work: 0 poles, 1 gantries, 2 wires
|
||||
int gantry_hang{0}; // the next cantilevers on the selected gantry: 0 on drops of the beam, 1 straight on its masts
|
||||
};
|
||||
catenary_tool m_catenary;
|
||||
void catenary_scan();
|
||||
bool catenary_spot_at(TTrack &Track, int const Path, glm::dvec3 const &Point, glm::dvec3 const &Cursor, int const Side, catenary_spot &Spot) const;
|
||||
// a pole of this type can't stand there: its group doesn't stand by switches and a switch is by it
|
||||
bool catenary_switch_error(std::string const &Pole, glm::dvec3 const &Foot, TTrack const *Track) const;
|
||||
bool catenary_switch_error(std::size_t const Index) const; // of a placed pole, remembered until it moves or changes type
|
||||
struct switch_check
|
||||
{
|
||||
glm::dvec3 foot{0.0};
|
||||
std::string pole;
|
||||
bool error{false};
|
||||
};
|
||||
mutable std::vector<std::pair<TTrack const *, int>> m_switch_paths; // the paths of switches, gathered again when the number of tracks changes
|
||||
mutable std::size_t m_switch_tracks{static_cast<std::size_t>(-1)};
|
||||
mutable std::map<std::size_t, switch_check> m_switch_checks;
|
||||
void catenary_compose(catenary_spot &Spot, double const Clearance, double const Stagger, bool const Toward, std::string const &Pole = {}) const;
|
||||
bool catenary_on_mast(catenary::gantry const &Gantry, double const Stagger, catenary_spot &Spot) const;
|
||||
catenary_spot const *catenary_spot_of(std::size_t const Index);
|
||||
int catenary_hit() const;
|
||||
int catenary_span_hit() const;
|
||||
void catenary_press(track_intent const &Intent);
|
||||
void catenary_select(int const Index);
|
||||
void catenary_apply(catenary_spot const &Spot);
|
||||
void catenary_copy(std::vector<std::size_t> const &Targets);
|
||||
bool catenary_propose_toward(bool &Toward);
|
||||
void catenary_place(catenary_spot const &Spot);
|
||||
void catenary_chain_apply();
|
||||
void catenary_connect(std::size_t const To);
|
||||
int catenary_gantry_hit() const;
|
||||
bool catenary_gantry_beam(std::size_t const Index, glm::dvec3 &From, glm::dvec3 &To, double &Bottom) const;
|
||||
bool catenary_gantry_second(glm::dvec3 const &Point, glm::dvec3 &Second, std::string &Beam) const;
|
||||
glm::dvec3 catenary_mast_point() const;
|
||||
// the face of the mast from the axis of the nearest track (within 20 m); false: no track near
|
||||
bool catenary_mast_face(std::string const &Mast, glm::dvec3 const &Point, double &Face, glm::dvec2 &Away) const;
|
||||
// the selected gantry (all its spans and what hangs on them) moved in the plan
|
||||
void catenary_gantry_shift(glm::dvec2 const &Shift);
|
||||
// the place of the first mast at Axis from the axis of the track nearest to Point, on the side of Point; false: no track near
|
||||
bool catenary_along_track(glm::dvec3 const &Point, double const Axis, glm::dvec3 &Place) const;
|
||||
bool catenary_on_gantry(catenary_spot &Spot);
|
||||
void catenary_drag_update();
|
||||
// the selected gantry anew: another beam, masts, turned around its middle (degrees), or square to the nearest track
|
||||
void catenary_gantry_reshape(std::string const &Beam, double const Turn, bool const Square);
|
||||
void catenary_release();
|
||||
void catenary_gantry_hangers(std::size_t const Gantry, std::vector<std::pair<std::size_t, catenary::suspension>> &Hangers) const;
|
||||
bool catenary_delete_selected();
|
||||
bool catenary_undo();
|
||||
void render_catenary_ui();
|
||||
bool render_catenary_catalog_ui();
|
||||
void render_catenary_chain_ui();
|
||||
// the anchors at both ends of the selected chain: add, settings, remove
|
||||
void render_catenary_anchor_ui(std::size_t Chain);
|
||||
// the anchor of the chain at its start (Start) or end; catenary_anchor_size() when none
|
||||
std::size_t catenary_anchor_of(catenary::chain const &Chain, std::string const &File, bool Start) const;
|
||||
void render_catenary_cantilever_ui();
|
||||
void render_catenary_wires_ui();
|
||||
void catenary_choose_page(int const Page);
|
||||
void draw_catenary_overlay() const;
|
||||
std::string catenary_intent_label(catenary_spot const &Spot) const;
|
||||
// the hooks of editor_mode
|
||||
bool catenary_intent(track_intent &Intent);
|
||||
std::string catenary_mode_name() const;
|
||||
void catenary_key_hints(std::vector<key_hint> &Hints) const;
|
||||
bool catenary_on_key(int const Key, int const Action, int const Mods);
|
||||
};
|
||||
@@ -577,9 +577,9 @@ void editor_mode::restore_track_snapshot(EditorSnapshot const &Snapshot, std::ve
|
||||
profile_restore();
|
||||
}
|
||||
|
||||
std::array<editor_mode::track_mode, 12> const &editor_mode::track_modes()
|
||||
std::array<editor_mode::track_mode, 13> const &editor_mode::track_modes()
|
||||
{
|
||||
static std::array<track_mode, 12> const modes{{
|
||||
static std::array<track_mode, 13> 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"},
|
||||
{"Switch", "T", track_tab::turnout, "Puts switches into the selected straight or curve, edits the geometry of the selected switch"},
|
||||
@@ -587,6 +587,7 @@ std::array<editor_mode::track_mode, 12> const &editor_mode::track_modes()
|
||||
{"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"},
|
||||
{"Catenary", "N", track_tab::catenary, "Poles with cantilevers by the track, the card chosen from the catalogue by the distance of the pole; the spans checked against the catalogue"},
|
||||
{"Objects", "B", track_tab::lineside, "Along the track: hectometre posts, fouling point markers, a vehicle to drive"},
|
||||
{"Profile", "P", track_tab::profile, "Vertical profile (grade line) along the line"},
|
||||
{"Speed", "V", track_tab::speed, "Speed limits of the paths against the speed their geometry allows"},
|
||||
@@ -644,6 +645,9 @@ void editor_mode::show_track_tab(track_tab const Tab)
|
||||
signal_scan();
|
||||
signal_refresh(true);
|
||||
break;
|
||||
case track_tab::catenary:
|
||||
catenary_scan();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -719,6 +723,8 @@ std::string editor_mode::track_mode_name() const
|
||||
if (m_signal.placing)
|
||||
return STR_C("Signal: drag along the track sets the direction of the trains, release to place it");
|
||||
return signal_armed() != nullptr ? STR_C("Signal: LMB by the track places it on that side") : STR_C("Signal: choose its type below");
|
||||
case track_tab::catenary:
|
||||
return catenary_mode_name();
|
||||
case track_tab::turntable:
|
||||
if (m_turntable.placing)
|
||||
return STR_C("Turntable: drag to turn the bridge, release to place it");
|
||||
@@ -737,6 +743,7 @@ void editor_mode::render_track_inspector()
|
||||
if (false == m_track_window_open || m_track_tab != track_tab::lineside)
|
||||
m_sweep.open = m_hekto.open = m_fouling.open = m_parallel.open = m_vehicle.open = false;
|
||||
ui()->set_track(m_track_window_open);
|
||||
ui()->set_track_title(m_track_tab == track_tab::catenary ? STR("Catenary") : std::string{});
|
||||
if (false == m_track_window_open)
|
||||
{
|
||||
// a closed window takes its mode with it
|
||||
@@ -774,9 +781,13 @@ void editor_mode::render_track_tool_options()
|
||||
{
|
||||
auto *track{selected_track()};
|
||||
// the tools themselves are in the toolbar
|
||||
render_track_search();
|
||||
ImGui::Spacing();
|
||||
render_track_guide();
|
||||
if (m_track_tab != track_tab::catenary)
|
||||
{
|
||||
// the catenary is a field of work of its own: no search of the paths there
|
||||
render_track_search();
|
||||
ImGui::Spacing();
|
||||
render_track_guide();
|
||||
}
|
||||
switch (m_track_tab)
|
||||
{
|
||||
case track_tab::lay:
|
||||
@@ -804,6 +815,7 @@ void editor_mode::render_track_tool_options()
|
||||
break;
|
||||
case track_tab::lineside: render_lineside_ui(); break;
|
||||
case track_tab::signals: render_signal_ui(); break;
|
||||
case track_tab::catenary: render_catenary_ui(); break;
|
||||
case track_tab::turntable: render_turntable_ui(); break;
|
||||
default:
|
||||
render_track_set_ui();
|
||||
@@ -3515,6 +3527,10 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
|
||||
if (m_signal.selected != 0)
|
||||
hints.push_back({"Del", "removes the selected signal with its event"});
|
||||
}
|
||||
else if (m_track_window_open && m_track_tab == track_tab::catenary)
|
||||
{
|
||||
catenary_key_hints(hints);
|
||||
}
|
||||
else if (m_track_window_open && m_track_tab == track_tab::joints)
|
||||
hints = {{"LMB on a row", "show the place"}, {"Fix", "joins the ends, aligns them"}};
|
||||
else if (m_track_window_open && m_track_tab == track_tab::infra)
|
||||
@@ -5053,8 +5069,11 @@ void editor_mode::draw_build_overlay() const
|
||||
}
|
||||
};
|
||||
auto const &display{ImGui::GetIO().DisplaySize};
|
||||
// the ends of all the paths; not in the catenary, where they're of no use and cost a lot in a big scenery
|
||||
for (auto const *track : simulation::Paths.sequence())
|
||||
{
|
||||
if (m_track_tab == track_tab::catenary)
|
||||
break;
|
||||
if (track == nullptr || track->m_editorremoved || track->m_paths.empty())
|
||||
continue;
|
||||
for (auto const &path : track->m_paths)
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace
|
||||
using geometry::bezier;
|
||||
|
||||
float const kHoverPixels{12.0f};
|
||||
double const kCatenaryHoverRange{1500.0}; // m from the camera: the paths the catenary looks at under the cursor
|
||||
double const kHoverLabelDelay{0.35}; // s the cursor rests on a path before its data shows up
|
||||
double const kFocusDistance{25.0};
|
||||
auto const kContextClick{std::chrono::milliseconds(350)};
|
||||
@@ -106,6 +107,9 @@ editor_mode::track_hover editor_mode::track_under_cursor() const
|
||||
for (int i = 0; i < static_cast<int>(track->m_paths.size()); ++i)
|
||||
{
|
||||
bezier const curve{track->m_paths[i]};
|
||||
// the catenary works close to the camera: the paths far away aren't looked at (in a big scenery they cost a lot)
|
||||
if (m_track_tab == track_tab::catenary && glm::distance(curve.point(0.5), glm::dvec3{Global.pCamera.Pos}) > curve.plan_length() * 0.5 + kCatenaryHoverRange)
|
||||
continue;
|
||||
auto const count{std::clamp(static_cast<int>(curve.plan_length() / 3.0), 6, 64)};
|
||||
auto previous{curve.point(0.0)};
|
||||
ImVec2 from;
|
||||
@@ -181,7 +185,7 @@ void editor_mode::draw_track_hover() const
|
||||
bool editor_mode::track_gesture_on() const
|
||||
{
|
||||
return mouseHold || m_track_set_using || m_track_box.active || m_input.mouse.button(GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS || m_track_gizmo_using || m_route_gizmo_using || m_extend.active || m_switch.placing || m_straights.dragging || m_straights.tool_mouse ||
|
||||
m_point_drag.active || m_handle_drag.active || m_sweep.dragging || m_turntable.placing || m_signal.placing || m_signal.moving || ImGuizmo::IsUsing();
|
||||
m_point_drag.active || m_handle_drag.active || m_sweep.dragging || m_turntable.placing || m_signal.placing || m_signal.moving || catenary_dragging() || ImGuizmo::IsUsing();
|
||||
}
|
||||
|
||||
editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
@@ -220,6 +224,11 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
}
|
||||
if (m_track_tab == track_tab::turntable)
|
||||
return turntable_intent(ground, shift);
|
||||
if (m_track_tab == track_tab::catenary)
|
||||
{
|
||||
catenary_intent(intent);
|
||||
return intent;
|
||||
}
|
||||
if (m_track_tab == track_tab::signals)
|
||||
{
|
||||
if (auto const hit{signal_hit()}; hit >= 0)
|
||||
@@ -453,6 +462,7 @@ void editor_mode::track_press(track_intent const &Intent)
|
||||
case kind::turntable_fit: turntable_press(Intent); return;
|
||||
case kind::signal_place:
|
||||
case kind::signal_move: signal_press(Intent); return;
|
||||
case kind::catenary: catenary_press(Intent); return;
|
||||
case kind::select:
|
||||
case kind::none:
|
||||
{
|
||||
|
||||
@@ -185,6 +185,15 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
||||
[this]() { m_gauge.open = !m_gauge.open; }});
|
||||
break;
|
||||
}
|
||||
case work_area::catenary:
|
||||
{
|
||||
// the pages of the catenary: poles with cantilevers, gantries, the wires of the chains
|
||||
auto const page{catenary_page()};
|
||||
Buttons.push_back({icon::catenary, STR_C("Poles"), nullptr, STR_C("Poles with cantilevers: LMB by a track places one, LMB on a pole selects it"), page == 0, [this]() { catenary_choose_page(0); }});
|
||||
Buttons.push_back({icon::gantry, STR_C("Gantries"), nullptr, STR_C("Gantries: masts and beams, the cantilevers on their drops and masts"), page == 1, [this]() { catenary_choose_page(1); }});
|
||||
Buttons.push_back({icon::wires, STR_C("Wires"), nullptr, STR_C("The chains: the type of the network, the wires, the spans between the poles"), page == 2, [this]() { catenary_choose_page(2); }});
|
||||
break;
|
||||
}
|
||||
case work_area::roads:
|
||||
{
|
||||
auto &tool{m_roadtool};
|
||||
|
||||
@@ -736,7 +736,7 @@ void editor_ui::render_tool_options()
|
||||
name = STR_C("Copy to bank");
|
||||
break;
|
||||
case nodebank_panel::TRACK:
|
||||
name = STR_C("Tracks");
|
||||
name = m_tracktitle.empty() ? STR_C("Tracks") : m_tracktitle.c_str();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -55,6 +55,8 @@ class editor_ui : public ui_layer
|
||||
m_filloptions = std::move(Renderer);
|
||||
}
|
||||
// the open track window takes the mouse over, whichever toolset tab is chosen
|
||||
// the title of the tool options of the tracks; empty: "Tracks"
|
||||
void set_track_title(std::string Title) { m_tracktitle = std::move(Title); }
|
||||
void set_track(bool const Track)
|
||||
{
|
||||
m_track = Track;
|
||||
@@ -207,6 +209,7 @@ class editor_ui : public ui_layer
|
||||
bool m_sceneopen{true};
|
||||
std::function<void(scene::basic_node *, bool)> m_sceneselect;
|
||||
std::function<void()> m_tracktools;
|
||||
std::string m_tracktitle;
|
||||
std::function<void()> m_trackselection;
|
||||
int m_toolmode{-1}; // edit mode or field of work the tool options were drawn for the last time
|
||||
workspace m_workspace{workspace::none};
|
||||
|
||||
Reference in New Issue
Block a user