mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 05:09:20 +02:00
The track layout library came in as a subproject of its own -- its own CMakeLists, its own install and export rules, its own include tree -- which only made the build harder to follow now that everything else is a module. It is part of the editor, so it lives where the editor lives. - editor/plan_*.cppm / plan_*.cpp: the fifteen interface units and twelve implementation units, flat in editor/ beside editorTerrain and orthophoto, with the plan_ prefix keeping them clear of what was already there (editor/turnouts is the preset catalogue, so the geometry is plan_turnout_geometry). - modules are named eu07.editor.plan_*, like every other module in the tree. - namespaces move under the editor's own: editor::plan, editor::plan::geometry, ::io, ::render. The library's old name is gone from the sources and the docs. - every moved file carries the MPL header the rest of the tree carries; it had none. version.hpp went with the subproject: macros only, and unused. - the umbrella header is dropped -- nothing imported it. - the unit tests survive the fold: editor/tests, behind EU07_EDITOR_PLAN_TESTS (off by default), compiles the interfaces a second time into a small library of its own, because a test can only import modules from a target it links and linking the game would drag the whole simulator in. The code under test needs nothing but a compiler. 7/7 pass. - a switch may now be written with two dashes as well: --editor beside -editor. Builds with clang 22 (-DWITH_BETTER_RENDERER=OFF); -editor and --editor both come up in the editor on empty ground.
222 lines
9.3 KiB
C++
222 lines
9.3 KiB
C++
/*
|
|
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/.
|
|
*/
|
|
module;
|
|
#include <string>
|
|
#include <variant>
|
|
#include <vector>
|
|
#include "imgui/imgui.h"
|
|
|
|
export module eu07.application.planpanel;
|
|
import eu07.editor.plan_tilecache;
|
|
import eu07.editor.plan_layout;
|
|
import eu07.editor.plan_model;
|
|
import eu07.editor.plan_render;
|
|
import eu07.editor.plan_solution;
|
|
import eu07.editor.plan_scn_export;
|
|
import eu07.application.uilayer;
|
|
import eu07.editor.orthophoto;
|
|
|
|
export {
|
|
|
|
// track layout tool. the drawing happens in the viewport, which the tool puts into a top-down
|
|
// orthographic plan view; the panel holds only the controls. none of the geometry is computed here:
|
|
// the plan library solves the whole document and the panel paints what comes back.
|
|
//
|
|
// a track is a chain of elements, and every one of them says outright what it is: prosta of so many
|
|
// metres, luk of radius R turning so far, krzywa przejsciowa easing to R over so many metres. there
|
|
// is no second language of "run on until you reach that line" - laying by clicking along the ground
|
|
// works out the corner at the click and writes the numbers down.
|
|
//
|
|
// what one track keeps against another is said as a relation, not redrawn by hand: an element may be
|
|
// held parallel to another track's element at a given miedzytorze, and the solver moves the whole
|
|
// track until it really is.
|
|
class plan_panel : public ui_panel
|
|
{
|
|
|
|
public:
|
|
plan_panel(std::string const &Name, bool const Isopen);
|
|
|
|
void update() override;
|
|
void render_contents() override;
|
|
|
|
private:
|
|
using Document = editor::plan::Document;
|
|
using Element = editor::plan::Element;
|
|
using ElementId = editor::plan::ElementId;
|
|
using Solution = editor::plan::Solution;
|
|
using Track = editor::plan::Track;
|
|
using TrackId = editor::plan::TrackId;
|
|
using TurnoutId = editor::plan::TurnoutId;
|
|
|
|
// panels
|
|
void render_toolbar();
|
|
void render_elements();
|
|
void render_turnouts();
|
|
// joining two tracks into one: the radius a join may bend at, and the button that starts
|
|
// pointing at the ends to join. everything else about it happens on the map
|
|
void render_join();
|
|
void render_turnout_type(editor::plan::TurnoutType &Type_);
|
|
// the catalogue drawing of the chosen type, in its own window: the diverging path piece by
|
|
// piece, both tracks' rails, and the points a drawing is dimensioned from
|
|
void render_template_window();
|
|
void render_diagnostics();
|
|
void render_storage();
|
|
void export_scn(bool Run_);
|
|
void run_scn();
|
|
void seed_catalogue();
|
|
void render_newmap_dialog();
|
|
void render_location_dialog();
|
|
|
|
// scene
|
|
void handle_scene();
|
|
void draw_on_scene();
|
|
void go_to_plan();
|
|
|
|
// document
|
|
void solve();
|
|
void start_map(bool const Georeferenced, double const Originx, double const Originy);
|
|
Track *current_track();
|
|
Track const *current_track() const;
|
|
void new_track();
|
|
void delete_current_track();
|
|
void clear_selection();
|
|
// carries the track on to (X,Y). the track ends where it was last clicked, so that end is the
|
|
// corner: it gets rounded with an arc of m_corner_radius, the straight behind it gives up the
|
|
// tangent, and the new straight runs out to (X,Y) exactly. all of it lands in the document as
|
|
// ordinary elements with ordinary lengths
|
|
void append_point_to(double const X, double const Y);
|
|
// takes back one click: the trailing straight, its corner arc, and the tangent the arc had
|
|
// taken off the straight before it - which leaves the track ending on the click before
|
|
void drop_last_vertex();
|
|
// appends one element to the end of the current track, exactly as asked for
|
|
void append_element(editor::plan::Kind const Kind);
|
|
void drop_last_element();
|
|
void delete_selected_element();
|
|
void place_turnout_at(TrackId const On, double const Wx, double const Wy);
|
|
// re-lays the edited track along the lines its straights sat on before the change, so a new
|
|
// radius (or a new transition length) is absorbed by the corner it belongs to and nothing
|
|
// further down the track moves. false, with a reason, when it cannot be laid that way
|
|
bool refit_current_track(std::string &Why);
|
|
// swings the grabbed straight onto the line through its far end and (X,Y), then re-fits the
|
|
// arcs on either side of it. leaves the track untouched when that cannot be laid
|
|
void drag_straight_to(double const X, double const Y);
|
|
|
|
// hit tests, in screen pixels
|
|
// the end of a straight of the edited track: OutIndex is its element index, OutEnd 0 for the
|
|
// end it starts on and 1 for the end it runs out to
|
|
bool hit_straight_end(ImVec2 const &Mouse, std::size_t &OutIndex, int &OutEnd) const;
|
|
bool hit_element(ImVec2 const &Mouse, ElementId &OutElement, TrackId &OutTrack) const;
|
|
bool hit_turnout(ImVec2 const &Mouse, TurnoutId &OutTurnout) const;
|
|
// the loose end of any track: OutEnd 0 for the one it starts on, 1 for the one it runs out to.
|
|
// a track hanging on a turnout's port has no free start, so that one is not offered
|
|
bool hit_track_end(ImVec2 const &Mouse, float const Tolerance, TrackId &OutTrack, int &OutEnd) const;
|
|
// whether that end is loose at all: one that already stands on another track's end is joined
|
|
// to it, and there is nothing to join twice
|
|
bool loose_end(editor::plan::SolvedTrack const &Track_, int const End_) const;
|
|
// how an end reads for a join laid out of it or into it: one facing the wrong way for that
|
|
// is taken backwards, which is what turning the track round would do to it anyway
|
|
static editor::plan::geometry::Pose join_pose(editor::plan::SolvedTrack const &Track_, int const End_, bool const Leaving_);
|
|
// lays the join and leaves one track, saying what it cost
|
|
void join_ends(TrackId const A, int const Aend, TrackId const B, int const Bend);
|
|
// nearest station along a solved track's axis, for placing and sliding turnouts
|
|
bool station_on(TrackId const Track, double const Wx, double const Wy, double &OutStation) const;
|
|
TrackId nearest_track_axis(ImVec2 const &Mouse, float const Tolerance) const;
|
|
|
|
// members
|
|
Document m_document;
|
|
Solution m_solution;
|
|
std::vector<editor::plan::PlanPolyline> m_rails;
|
|
|
|
TrackId m_track{};
|
|
ElementId m_sel_element{};
|
|
TurnoutId m_sel_turnout{};
|
|
|
|
// a press on the ground does whatever is under it: picks up what is drawn there, or carries the
|
|
// current track on to there. every transient errand (placing a turnout, picking the element to
|
|
// run parallel to) is started from its own button, and Esc drops back out of it
|
|
bool m_dragging_turnout{false};
|
|
|
|
// grabbing a straight by one of its ends: which one, and the far end it swings about. the far
|
|
// end is captured once, at the grab, because re-fitting the arc behind it moves it
|
|
bool m_dragging_straight{false};
|
|
std::size_t m_drag_index{0};
|
|
int m_drag_end{0};
|
|
double m_pivot_x{0.0};
|
|
double m_pivot_y{0.0};
|
|
|
|
// an empty track needs two clicks before there is anything to carry on: the first only marks
|
|
// where it starts. after that the track always ends on the last click, which is the corner the
|
|
// next one is rounded at
|
|
bool m_pending{false};
|
|
double m_startx{0.0};
|
|
double m_starty{0.0};
|
|
|
|
// 0 idle, 1 waiting for a click on the through track
|
|
int m_pick_turnout{0};
|
|
// 0 idle, 1 waiting for the element the selected one is to be held parallel to
|
|
int m_pick_parallel{0};
|
|
// scalanie by pointing at it: 0 idle, 1 waiting for the first end, 2 for the second. a track
|
|
// joins onto another end to start, so which of the two ends is clicked says which way round
|
|
int m_pick_join{0};
|
|
TrackId m_join_first{};
|
|
int m_join_first_end{0};
|
|
|
|
// what the next appended element is made of
|
|
double m_new_radius{300.0};
|
|
double m_new_length{100.0};
|
|
int m_new_hand{1};
|
|
// the radius a corner is rounded with when laying by clicking
|
|
double m_corner_radius{300.0};
|
|
// the radius a join may bend at
|
|
double m_join_radius{300.0};
|
|
// miedzytorze a new hold is given, metres
|
|
double m_new_offset{4.75};
|
|
|
|
int m_turnout_type{0};
|
|
// which piece of the chosen type's geometry list is open for editing; -1 = none
|
|
int m_sel_piece{-1};
|
|
|
|
// the template drawing. a switch is thirty metres long and a metre and a half wide, so like
|
|
// every catalogue drawing this one is stretched across the track - the ratio is said on screen
|
|
bool m_show_template{false};
|
|
float m_tpl_zoom{1.0f};
|
|
float m_tpl_pan{0.0f}; // metres off centre, along the through track
|
|
float m_tpl_exagg{6.0f}; // przewyzszenie poprzeczne
|
|
bool m_tpl_rails{true};
|
|
bool m_tpl_marks{true};
|
|
// lukowanie in the drawing: the radius the tor zasadniczy is bent to, and which way
|
|
double m_tpl_bend_radius{0.0};
|
|
int m_tpl_bend_hand{0};
|
|
|
|
char m_namebuf[128]{};
|
|
std::string m_status;
|
|
char m_path[256]{"editor/plan.m0s"};
|
|
char m_scn_path[256]{"scenery/plan_export.scn"};
|
|
std::vector<std::string> m_scn_warnings;
|
|
// the exported scenery is opened in the editor by default: it stands up without a locomotive,
|
|
// and looking at what was drawn is what the export is usually for
|
|
bool m_scn_run_editor{true};
|
|
bool m_scn_trainset{true};
|
|
|
|
bool m_pickingplace{false};
|
|
double m_pickx{0.0};
|
|
double m_picky{0.0};
|
|
double m_mapviewx{0.0};
|
|
double m_mapviewy{0.0};
|
|
double m_mapscale{0.0};
|
|
|
|
editor::wms_image m_topomap{editor::plan::WmsConfig::geoportal_topo()};
|
|
editor::orthophoto_source m_ortho;
|
|
// 1 km topo cells for views wider than a kilometre (orto's 100 m grid is too dense there)
|
|
editor::orthophoto_source m_topo{editor::plan::WmsConfig::geoportal_topo(), 1000, "topo"};
|
|
bool m_showortho{true};
|
|
};
|
|
|
|
} // export
|