mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-30 16:40:28 +01:00
Editor: fold the plan library into the tree as modules, drop its own name
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.
This commit is contained in:
137
editor/plan_sketch.cppm
Normal file
137
editor/plan_sketch.cppm
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
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 <vector>
|
||||
|
||||
export module eu07.editor.plan_sketch;
|
||||
export import eu07.editor.plan_model;
|
||||
export import eu07.editor.plan_solution;
|
||||
|
||||
export {
|
||||
|
||||
namespace editor::plan {
|
||||
|
||||
/// Laying track by clicking along the ground.
|
||||
///
|
||||
/// The corner is worked out here, at the click, and written into the document as
|
||||
/// ordinary elements with ordinary lengths — a straight shortened by the
|
||||
/// tangent, an arc of the radius asked for, a straight running out to the point
|
||||
/// clicked. Nothing is left pointing at the drawing, so the numbers in the
|
||||
/// document are the numbers on the ground.
|
||||
|
||||
/// What rounding one corner costs.
|
||||
struct Corner {
|
||||
bool ok{false};
|
||||
/// How far back from the corner the arc starts, and how far past it the arc
|
||||
/// ends: R·tan(|Δ|/2). Both straights lose this much.
|
||||
double tangent{0.0};
|
||||
double arc_length{0.0}; ///< R·|Δ|
|
||||
int hand{0}; ///< +1 left, -1 right
|
||||
double deflection{0.0}; ///< Δ, radians, signed, + = left
|
||||
};
|
||||
|
||||
/// Rounds the corner between a heading in and a heading out with an arc of
|
||||
/// @p radius. Both headings are unit vectors in the plan's frame.
|
||||
///
|
||||
/// Not ok for a corner that does not bend, one that doubles back on itself, or a
|
||||
/// non-positive radius: none of those is an arc, and guessing one is how a fit
|
||||
/// used to quietly lay geometry nobody asked for.
|
||||
[[nodiscard]] Corner fit_corner(double in_hx, double in_hy, double out_hx, double out_hy,
|
||||
double radius);
|
||||
|
||||
/// The three elements a straight-arc-straight corner is made of, ready to append
|
||||
/// after @p incoming has been shortened by `corner.tangent`.
|
||||
[[nodiscard]] Element make_arc(Document& document, double radius, int hand, double length);
|
||||
[[nodiscard]] Element make_line(Document& document, double length);
|
||||
[[nodiscard]] Element make_clothoid(Document& document, double end_radius, int hand,
|
||||
double length);
|
||||
|
||||
/// Carries a change of radius or hand across the joint it belongs to.
|
||||
///
|
||||
/// A transition curve's radius is the radius it ends on, so it belongs to
|
||||
/// whatever comes after it: the arc it eases into, or nothing at all when a
|
||||
/// straight follows and it runs out flat at R=0. That is one number, not two, so
|
||||
/// editing either side of the joint carries the other with it — and the joint
|
||||
/// only ever looks forward. The transition behind an arc is the one that eases
|
||||
/// into it; the one in front of it eases into whatever is beyond, which is none
|
||||
/// of that arc's business.
|
||||
void sync_joint(Track& track, std::size_t at);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Straights as lines, and the arcs between them
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// The line a straight lies on: a point on it and the direction of travel.
|
||||
///
|
||||
/// This is what a straight really is once it is drawn — where it lies and which
|
||||
/// way it points. Its length is not part of it: that falls out of where the arcs
|
||||
/// at either end come off it.
|
||||
struct Support {
|
||||
double px{0.0}, py{0.0};
|
||||
double dx{1.0}, dy{0.0};
|
||||
};
|
||||
|
||||
/// What a track hangs on: the line under every one of its straights, and where
|
||||
/// the first and last of them begin and end.
|
||||
///
|
||||
/// The corners between two straights are not in here, because they do not have
|
||||
/// to be: given the lines, each of them is worked out. A corner hanging off
|
||||
/// either end of the chain — a track that starts or finishes mid-curve — is not
|
||||
/// in here either, for the opposite reason: it has nothing on its far side to be
|
||||
/// fitted against, so it is carried along exactly as it was authored.
|
||||
struct Skeleton {
|
||||
std::vector<Support> lines;
|
||||
double start_x{0.0}, start_y{0.0}; ///< where the first straight begins
|
||||
double end_x{0.0}, end_y{0.0}; ///< where the last straight ends
|
||||
/// Where the chain has to begin, and whether that is a place anybody may
|
||||
/// move. A branch on a turnout's port may not: its first curve is laid from
|
||||
/// the frog and the line under the straight after it follows wherever that
|
||||
/// curve comes out, rather than the curve being slid along a line drawn
|
||||
/// before the edit.
|
||||
bool pinned{false};
|
||||
geometry::Pose begins{};
|
||||
};
|
||||
|
||||
/// Pulls @p track's skeleton out of @p solved.
|
||||
///
|
||||
/// A chain must read as straights with corners between them — a corner being any
|
||||
/// run of arcs and transition curves that turns one way, one arc or a basket of
|
||||
/// them. Two straights may never touch: two straights end to end are one
|
||||
/// straight. A track with no straight at all has no skeleton, and says so.
|
||||
[[nodiscard]] bool skeleton_of(const Track& track, const SolvedTrack& solved,
|
||||
Skeleton& out, std::string& why);
|
||||
|
||||
/// Rewrites @p track to run along @p skeleton, keeping every arc's radius and
|
||||
/// hand, and every transition curve's length.
|
||||
///
|
||||
/// Each corner with a straight on both sides is fitted: the transitions turn what
|
||||
/// they turn, the arcs share out what is left of the corner in the proportions
|
||||
/// they were drawn with — so a basket curve stays that basket, tighter or wider —
|
||||
/// and the whole corner is then slid along the line it leaves until it lands on
|
||||
/// the line it joins. The turn is taken the way the arcs go, so a corner may run
|
||||
/// past a half circle, up to a full one, and nothing shortens it to the way round
|
||||
/// that happens to be shorter.
|
||||
///
|
||||
/// A corner hanging off either end of the chain keeps exactly what it was given:
|
||||
/// there is no second line to fit it against, so a track ending mid-curve simply
|
||||
/// ends where that curve takes it.
|
||||
///
|
||||
/// The skeleton's ends stay put and the anchor follows them — unless the track is
|
||||
/// pinned to a turnout's port, which is not an anchor anyone may move: a change
|
||||
/// that would drag the branch off its frog is refused instead.
|
||||
///
|
||||
/// False, with a reason, when the skeleton cannot carry the chain. Nothing is
|
||||
/// written to @p track unless all of it works out.
|
||||
[[nodiscard]] bool lay_along_skeleton(Track& track, const Skeleton& skeleton,
|
||||
std::string& why);
|
||||
|
||||
} // namespace editor::plan
|
||||
|
||||
} // export
|
||||
Reference in New Issue
Block a user