mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-29 18:37:29 +01:00
Merge remote-tracking branch 'jano211/siec-radio' into feat/renderers-cleanup
This commit is contained in:
@@ -20,6 +20,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"
|
||||
@@ -1568,6 +1569,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
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ extern char **environ;
|
||||
#include "editor/editorFormat.hpp"
|
||||
#include "editor/editorAlignmentStore.hpp"
|
||||
#include "editor/editorSwitchStore.hpp"
|
||||
#include "world/catenary_scene.h"
|
||||
#include "editor/editorGeometry.hpp"
|
||||
#include "editor/editorIcons.hpp"
|
||||
#include "utilities/translation.h"
|
||||
@@ -1276,6 +1277,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)
|
||||
@@ -1443,6 +1445,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)
|
||||
{
|
||||
@@ -2986,6 +2993,23 @@ bool editor_mode::save()
|
||||
switch_store::tidy();
|
||||
switch_store::settle();
|
||||
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});
|
||||
@@ -3034,6 +3058,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;
|
||||
@@ -3815,6 +3842,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ą
|
||||
}
|
||||
// the layers of clouds, the fog and a weather report, as the weather section of a scenery describes them
|
||||
if (ImGui::CollapsingHeader(STR_C("Clouds, fog and weather report")))
|
||||
@@ -4668,7 +4696,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;
|
||||
@@ -4684,7 +4712,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;
|
||||
@@ -4713,8 +4745,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()};
|
||||
@@ -5610,7 +5643,7 @@ void editor_mode::render_shortcuts_window()
|
||||
{"Ctrl+Shift+F11", "Export scenery dump"},
|
||||
{"F11", "Leave the editor"},
|
||||
{"F10", "Quit the simulator"}}},
|
||||
{"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)"},
|
||||
@@ -6362,6 +6395,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)
|
||||
@@ -6429,6 +6464,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.
|
||||
@@ -6452,6 +6491,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: handled = ui()->mode() != nodebank_panel::TRACK; if (handled) choose_edit_mode(nodebank_panel::MODIFY); break;
|
||||
case GLFW_KEY_2: handled = ui()->mode() != nodebank_panel::TRACK; if (handled) choose_edit_mode(nodebank_panel::ADD); break;
|
||||
@@ -6544,6 +6584,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;
|
||||
}
|
||||
@@ -6886,6 +6929,8 @@ void editor_mode::on_mouse_button(int const Button, int const Action, int const
|
||||
signal_release();
|
||||
if (m_switch.slide.active)
|
||||
switch_slide_finish();
|
||||
if (catenary_dragging())
|
||||
catenary_release();
|
||||
}
|
||||
|
||||
m_dragging = false;
|
||||
|
||||
@@ -58,6 +58,8 @@ struct vehicle_desc;
|
||||
struct skin_set;
|
||||
}
|
||||
|
||||
struct catenary_editor; // application/editormodecatenary.h
|
||||
|
||||
class editor_mode : public application_mode, private editor_track::observer
|
||||
{
|
||||
|
||||
@@ -768,7 +770,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);
|
||||
@@ -1540,7 +1543,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, parallel };
|
||||
enum class track_tab { straights, route, path, turnout, profile, speed, joints, infra, lay, lineside, turntable, signals, parallel, catenary };
|
||||
struct track_mode
|
||||
{
|
||||
char const *label;
|
||||
@@ -1550,7 +1553,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
editor_icons::icon picture;
|
||||
int family; // 0 builds the track, 1 equips it, 2 checks it
|
||||
};
|
||||
static std::array<track_mode, 11> const &track_modes();
|
||||
static std::array<track_mode, 12> 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
|
||||
@@ -1636,7 +1639,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, switch_slide, pick_style, fouling };
|
||||
enum class kind { none, gizmo, select, point, box, straight_set, straight_break, detour, straight_tool, straight_handle, route_vertex, route_grip, switch_at, lay, lay_end, sweep, turntable_place, turntable_exit, turntable_fit, spread, extend_end, signal_place, signal_move, switch_slide, pick_style, fouling, catenary };
|
||||
kind what{kind::none};
|
||||
TTrack *track{nullptr};
|
||||
int path{0};
|
||||
@@ -1645,6 +1648,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);
|
||||
@@ -2176,6 +2180,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
|
||||
{
|
||||
|
||||
4685
application/editormodecatenary.cpp
Normal file
4685
application/editormodecatenary.cpp
Normal file
File diff suppressed because it is too large
Load Diff
260
application/editormodecatenary.h
Normal file
260
application/editormodecatenary.h
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
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, anchor };
|
||||
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
|
||||
int inward{0}; // the centre of the bend: +1 on the right of the direction of the path, -1 on the left, 0 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 continue_pending{-1}; // the chain goes on from this pole, from the next frame of the panel (the button is in the middle of it)
|
||||
bool insert_spans{true}; // a pole placed in a span of a chain goes into the chain between the two poles of the span
|
||||
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
|
||||
int umbrella_from{-1}; // an umbrella from this suspension: the next LMB by a track puts the second cantilever on its pole (or drop)
|
||||
int anchor_pick{-1}; // anchoring this chain to an existing pole: the next pole clicked carries the tensioning device
|
||||
bool anchor_pick_start{false}; // ... at the start of the chain, otherwise at its end
|
||||
bool anchor_pick_contact{false}; // ... the contact wires only (anchored apart from the messenger)
|
||||
int anchor_selected{-1}; // the anchor picked in the view: its chain is shown, the panel marks it, Del removes it
|
||||
bool anchor_scroll{false}; // the panel scrolls to the anchor picked in the view, once
|
||||
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;
|
||||
// superelevation of the track at the spot (radians, unsigned) and the horizontal shift of the axis of a leaning
|
||||
// pantograph at Height above the rail heads, towards the inside of the bend (table 23-0007, curve with superelevation)
|
||||
static double catenary_cant(catenary_spot const &Spot);
|
||||
static glm::dvec3 catenary_cant_shift(catenary_spot const &Spot, double Height);
|
||||
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);
|
||||
// the second cantilever of an umbrella on the pole (or drop) of tool.umbrella_from, towards this track; false when it can't
|
||||
// be put there (Spot.problem says why when Spot.card is 0)
|
||||
bool catenary_umbrella_spot(TTrack &Track, int Path, catenary_spot &Spot);
|
||||
void catenary_umbrella_place(catenary_spot const &Spot);
|
||||
// the two cantilevers of the umbrella of this suspension become separate ones
|
||||
void catenary_umbrella_break(std::size_t Index);
|
||||
// a cantilever of an umbrella or of spread cantilevers: composed with its pole (and its console mount) where they are
|
||||
void catenary_keep_pole(catenary_spot &Spot, catenary::suspension const &Current, double Stagger, bool Toward) const;
|
||||
// spread cantilevers on the console of the pole: this one onto the first mount, a second one onto the other, same track
|
||||
void catenary_spread_create(std::size_t Index);
|
||||
// the pole of an umbrella or of spread cantilevers moved to Foot (rail heads): both cantilevers go with it
|
||||
// (Panel: from the distance slider - the selected one takes the stagger of the panel, the slider is one undo group)
|
||||
void catenary_pair_move(std::size_t Selected, glm::dvec3 const &Foot, bool Panel);
|
||||
// a third cantilever on the pole of spread cantilevers, in the axis of the pole, to the same track (shared_pole)
|
||||
void catenary_third_create(std::size_t Index);
|
||||
// the span of a chain the spot falls in (in the plan: the wire point near the line of the span, between its ends)
|
||||
struct chain_insert
|
||||
{
|
||||
int chain{-1};
|
||||
std::size_t after{0}; // the new pole goes after this position of the chain
|
||||
std::size_t from{0}, to{0}; // the suspensions at both ends of the span
|
||||
};
|
||||
bool catenary_insert_at(catenary_spot const &Spot, chain_insert &Insert) const;
|
||||
// the next pole placed starts a new chain
|
||||
void catenary_chain_end();
|
||||
// the next poles placed go on from this pole: at the end (or the start) of its chain, or a new chain from it;
|
||||
// false when the pole is in the middle of a chain
|
||||
bool catenary_chain_continue(std::size_t Pole);
|
||||
// the chain block of the poles page: what the next click does, end, anchor, go on from the selected pole
|
||||
void render_catenary_chain_state();
|
||||
void catenary_chain_apply();
|
||||
void render_catenary_messenger_from(std::size_t Chain);
|
||||
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, bool Contact = false) const;
|
||||
// anchors the start or the end of the chain: on a new pole past the last one, or (On >= 0) on that existing pole
|
||||
bool catenary_anchor_create(std::size_t Chain, bool Start, int On, bool Contact = false);
|
||||
// removes the anchor at the start or the end of the chain (one undo step with the chain)
|
||||
void catenary_anchor_delete(std::size_t Chain, bool Start, bool Contact = false);
|
||||
// the anchor whose tensioning device is under the cursor; -1 if none
|
||||
int catenary_anchor_hit() const;
|
||||
// shows the chain in the panel as a click on its span does
|
||||
void catenary_chain_show(int Chain);
|
||||
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);
|
||||
};
|
||||
@@ -348,9 +348,9 @@ void editor_mode::restore_track_snapshot(EditorSnapshot const &Snapshot, std::ve
|
||||
profile_restore();
|
||||
}
|
||||
|
||||
std::array<editor_mode::track_mode, 11> const &editor_mode::track_modes()
|
||||
std::array<editor_mode::track_mode, 12> const &editor_mode::track_modes()
|
||||
{
|
||||
static std::array<track_mode, 11> const modes{{
|
||||
static std::array<track_mode, 12> const modes{{
|
||||
{"Select", "Esc", track_tab::path, "LMB on a path selects it: its points, control vectors and parameters", editor_icons::icon::select, 0},
|
||||
{"Lay track", "L", track_tab::lay, "Lays new track through the clicked points, on the ground or from a free end of a track", editor_icons::icon::lay_track, 0},
|
||||
{"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", editor_icons::icon::curve, 0},
|
||||
@@ -358,6 +358,7 @@ std::array<editor_mode::track_mode, 11> const &editor_mode::track_modes()
|
||||
{"Parallel", "N", track_tab::parallel, "A second track beside a track: LMB on it, then the side and the spacing", editor_icons::icon::parallel, 0},
|
||||
{"Turntable", "U", track_tab::turntable, "Places a turntable, leads tracks out of it and fits the tracks around to it", editor_icons::icon::turntable, 1},
|
||||
{"Signals", "H", track_tab::signals, "Signals by the track, from the templates of the scenery, with the event the train reads them by", editor_icons::icon::signal, 1},
|
||||
{"Catenary", "F6", 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", editor_icons::icon::catenary, 1},
|
||||
{"Objects", "B", track_tab::lineside, "Along the track: hectometre posts, fouling point markers, trainsets", editor_icons::icon::objects, 1},
|
||||
{"Profile", "P", track_tab::profile, "Vertical profile (grade line) along the line", editor_icons::icon::profile, 2},
|
||||
{"Speed", "V", track_tab::speed, "Speed limits of the paths against the speed their geometry allows", editor_icons::icon::speed, 2},
|
||||
@@ -416,6 +417,9 @@ void editor_mode::show_track_tab(track_tab const Wanted)
|
||||
case track_tab::signals:
|
||||
signal_refresh(true);
|
||||
break;
|
||||
case track_tab::catenary:
|
||||
catenary_scan();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -491,6 +495,7 @@ std::string editor_mode::track_mode_name() const
|
||||
case track_tab::parallel: return STR_C("Parallel track");
|
||||
case track_tab::signals: return STR_C("Signal");
|
||||
case track_tab::turntable: return STR_C("Turntable");
|
||||
case track_tab::catenary: return catenary_mode_name();
|
||||
default: return STR_C("Select");
|
||||
}
|
||||
}
|
||||
@@ -511,6 +516,7 @@ void editor_mode::render_track_inspector()
|
||||
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
|
||||
@@ -549,9 +555,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();
|
||||
}
|
||||
// the texts of the tools go on to the next line at the edge of the panel, none of them makes it scroll sideways
|
||||
ImGui::PushTextWrapPos(0.0f);
|
||||
switch (m_track_tab)
|
||||
@@ -584,6 +594,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();
|
||||
@@ -1591,6 +1602,10 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
|
||||
hints = {{"LMB around it", "leads a track out"}, {"LMB on a free end", "fits that track to the turntable"}};
|
||||
else if (m_track_window_open && m_track_tab == track_tab::turntable)
|
||||
hints = {{"LMB", "places a new turntable"}};
|
||||
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)
|
||||
@@ -2038,6 +2053,8 @@ void editor_mode::draw_build_overlay() const
|
||||
auto const in_reach = [&](glm::dvec3 const &Point) { return Global.EditorOrtho || glm::distance(Point, eye) <= kDotsRange; };
|
||||
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)
|
||||
|
||||
@@ -44,6 +44,7 @@ using geometry::plan_of;
|
||||
float const kHoverPixels{12.0f};
|
||||
float const kFarHoverPixels{16.0f};
|
||||
double const kLinesFrom{0.5};
|
||||
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)};
|
||||
@@ -130,7 +131,9 @@ editor_mode::track_hover editor_mode::track_under_cursor(TTrack const *Only, flo
|
||||
for (int i = 0; i < static_cast<int>(track->m_paths.size()); ++i)
|
||||
{
|
||||
bezier const curve{track->m_paths[i]};
|
||||
if (cull && false == plan_near(curve, plan_of(origin), reach))
|
||||
// the catenary works close to the camera: the paths far away aren't looked at (in a big scenery they cost a lot)
|
||||
if ((cull && false == plan_near(curve, plan_of(origin), reach)) ||
|
||||
(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)};
|
||||
@@ -238,7 +241,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_dragging || 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 || m_switch.slide.active || ImGuizmo::IsUsing();
|
||||
m_point_drag.active || m_handle_drag.active || m_sweep.dragging || m_turntable.placing || m_signal.placing || m_signal.moving || m_switch.slide.active || catenary_dragging() || ImGuizmo::IsUsing();
|
||||
}
|
||||
|
||||
editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
@@ -286,6 +289,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)
|
||||
@@ -583,6 +591,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::switch_slide:
|
||||
if (Intent.track != nullptr)
|
||||
{
|
||||
|
||||
@@ -202,6 +202,15 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
||||
Buttons.back().accent = family_colour(2);
|
||||
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};
|
||||
|
||||
@@ -740,7 +740,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;
|
||||
@@ -218,6 +220,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