mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-03 19:00:22 +01:00
Editor checkpoint: turnout domain service, web->editor rename, Id-1 templates
Checkpoint of the editor branch so work isn't carried loose across a branch switch. Builds. - maj0sted turnout geometry moved into the domain: domain::lay_turnout lays the diverging path (pre-blade lead, blade at beta, arc of alfa-beta, frog rail) and solve_junction is a thin adapter onto it. - the maj0sted web/ tree renamed to editor/ (namespace and paths) - there is no WASM here, it's plain native C++ the editor calls. - click places the switch at its start (początek rozjazdu); the branch's leaving straight is locked tangent to the frog; switches can be slid along the through track and flipped L/P. - Polish turnout templates carry catalogue length (Id-1-consistent lengths), plus blade-angle and pre-blade fields (left 0 until the catalogue figures are in). - TURNOUT_SPEC.md: the Bezier-based runtime/model contract. - also folds in other pending branch changes (scenery, tests) to leave a clean tree.
This commit is contained in:
58
maj0sted/include/maj0sted/app/basket_draft.hpp
Normal file
58
maj0sted/include/maj0sted/app/basket_draft.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "maj0sted/editor/editor.hpp"
|
||||
#include "maj0sted/editor/ribbon.hpp"
|
||||
#include "maj0sted/editor/solve.hpp"
|
||||
|
||||
namespace maj0sted::app {
|
||||
|
||||
struct BasketDraft {
|
||||
bool active{false};
|
||||
double x0{0.0};
|
||||
double y0{0.0};
|
||||
double az0{0.0};
|
||||
int dir{1};
|
||||
double entry_t{0.0};
|
||||
double exit_t{0.0};
|
||||
std::vector<maj0sted::editor::CompoundArcSpec> arcs;
|
||||
double preview_next_r{300.0};
|
||||
int attach_str{-1};
|
||||
int attach_end{-1};
|
||||
int reedit_gap{-1};
|
||||
maj0sted::editor::GapFit reedit_backup{};
|
||||
};
|
||||
|
||||
[[nodiscard]] maj0sted::editor::RibbonRequest draft_to_ribbon(const BasketDraft& draft);
|
||||
|
||||
[[nodiscard]] std::vector<maj0sted::editor::PlanPolyline> preview_basket_draft(
|
||||
BasketDraft& draft, double fallback_next_r = 300.0);
|
||||
|
||||
void start_basket_draft_from_end(BasketDraft& draft,
|
||||
const maj0sted::editor::StraightSpec& straight,
|
||||
int straight_index, int end, double default_r = 300.0);
|
||||
|
||||
[[nodiscard]] bool reopen_basket_draft(BasketDraft& draft,
|
||||
maj0sted::editor::NiweletaSpec& niweleta,
|
||||
std::size_t gap,
|
||||
const maj0sted::editor::NiweletaPolys* solved);
|
||||
|
||||
void discard_basket_draft(BasketDraft& draft, maj0sted::editor::NiweletaSpec* niweleta);
|
||||
|
||||
[[nodiscard]] bool anchor_basket_draft(BasketDraft& draft,
|
||||
maj0sted::editor::NiweletaSpec& niweleta,
|
||||
std::size_t gap);
|
||||
|
||||
struct FinishBasketDraftResult {
|
||||
bool ok{false};
|
||||
std::string status;
|
||||
};
|
||||
|
||||
[[nodiscard]] FinishBasketDraftResult finish_basket_draft(
|
||||
BasketDraft& draft, maj0sted::editor::NiweletaSpec& niweleta,
|
||||
std::vector<maj0sted::editor::NiweletaSpec>& all_niwelety, int niweleta_index,
|
||||
double finish_straight_m);
|
||||
|
||||
} // namespace maj0sted::app
|
||||
@@ -5,13 +5,13 @@
|
||||
#include <vector>
|
||||
|
||||
#include "maj0sted/domain/map_project.hpp"
|
||||
#include "maj0sted/web/editor.hpp"
|
||||
#include "maj0sted/editor/editor.hpp"
|
||||
|
||||
namespace maj0sted::app {
|
||||
|
||||
struct EditorDocument {
|
||||
std::vector<maj0sted::web::NiweletaSpec> niwelety;
|
||||
std::vector<maj0sted::web::Junction> junctions;
|
||||
std::vector<maj0sted::editor::NiweletaSpec> niwelety;
|
||||
std::vector<maj0sted::editor::Junction> junctions;
|
||||
double view_x{0.0};
|
||||
double view_y{0.0};
|
||||
double view_extent{0.0};
|
||||
|
||||
12
maj0sted/include/maj0sted/app/straight_constraints.hpp
Normal file
12
maj0sted/include/maj0sted/app/straight_constraints.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "maj0sted/editor/editor.hpp"
|
||||
|
||||
namespace maj0sted::app {
|
||||
|
||||
void apply_straight_constraints(std::vector<maj0sted::editor::NiweletaSpec>& niwelety);
|
||||
void align_gap_fits(maj0sted::editor::NiweletaSpec& niweleta);
|
||||
|
||||
} // namespace maj0sted::app
|
||||
85
maj0sted/include/maj0sted/domain/geometry/turnout.hpp
Normal file
85
maj0sted/include/maj0sted/domain/geometry/turnout.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "maj0sted/domain/geometry/segment_layout.hpp" // Pose
|
||||
|
||||
namespace maj0sted::domain {
|
||||
|
||||
/// The crossing mark of a turnout — the skos 1:n. It is the tangent of the angle
|
||||
/// between the through and diverging tracks, so it fixes the total angle the
|
||||
/// diverging curve must turn through: a turnout is 1:9, 1:12, 1:18,5 and so on.
|
||||
class CrossingMark {
|
||||
public:
|
||||
explicit CrossingMark(double denominator) noexcept : denominator_{denominator} {}
|
||||
|
||||
[[nodiscard]] double denominator() const noexcept { return denominator_; }
|
||||
/// The angle between the tracks, radians. Zero for a non-positive mark.
|
||||
[[nodiscard]] double angle() const noexcept;
|
||||
|
||||
private:
|
||||
double denominator_;
|
||||
};
|
||||
|
||||
/// Which way the branch leaves the through track.
|
||||
enum class DivergeSide { Left, Right };
|
||||
|
||||
/// One arc of a turnout's diverging curve: its radius and — unless it is the
|
||||
/// closing arc — its fixed length and the clothoid easing it into the next arc.
|
||||
struct TurnoutArc {
|
||||
double radius{0.0};
|
||||
double length{0.0}; ///< fixed length; ignored for the closing arc
|
||||
double transition_to_next{0.0}; ///< clothoid to the next arc (0 = none)
|
||||
};
|
||||
|
||||
/// The shape of a turnout's diverging curve. One arc is the everyday turnout; two
|
||||
/// or more make a łuk koszowy. Whatever the shape, the curve turns through exactly
|
||||
/// the crossing angle — the closing (last) arc spends whatever deflection the
|
||||
/// earlier arcs and clothoids leave.
|
||||
struct DivergingCurve {
|
||||
std::vector<TurnoutArc> arcs; ///< at least one; the last one closes the turn
|
||||
double entry_transition{0.0}; ///< clothoid from the through track into the first arc
|
||||
double exit_transition{0.0}; ///< clothoid from the last arc back toward tangent
|
||||
};
|
||||
|
||||
/// A turnout (rozjazd), described the way a catalogue does: a crossing mark, the
|
||||
/// side it opens to, the free diverging curve inside it, and the length it spans
|
||||
/// from its start (początek rozjazdu) to its end (koniec rozjazdu) measured along
|
||||
/// the through track. The curve turns to the crossing angle and a straight frog
|
||||
/// rail carries the track on to that length.
|
||||
struct Turnout {
|
||||
CrossingMark mark;
|
||||
DivergeSide side{DivergeSide::Left};
|
||||
DivergingCurve curve;
|
||||
double length{0.0}; ///< catalogue length along the through track; 0 = a tangent-length rail
|
||||
};
|
||||
|
||||
/// One laid segment of the diverging path, as the constant/linear curvature the
|
||||
/// renderer and the fitter already share (see segment_layout): a straight when
|
||||
/// both curvatures are zero, an arc when they are equal, a clothoid otherwise.
|
||||
struct TurnoutSegment {
|
||||
double k0{0.0};
|
||||
double k1{0.0};
|
||||
double length{0.0};
|
||||
};
|
||||
|
||||
/// What a turnout works out to when laid from its start pose.
|
||||
struct TurnoutGeometry {
|
||||
bool valid{false};
|
||||
std::vector<TurnoutSegment> path; ///< diverging segments from the switch start to the frog
|
||||
geometry::Pose frog{}; ///< the end (koniec rozjazdu): position + heading at the crossing angle
|
||||
double tangent_front{0.0}; ///< theoretical tangent length, switch start to the crossing point
|
||||
double tangent_back{0.0}; ///< theoretical tangent length, crossing point to the frog
|
||||
double diverging_length{0.0}; ///< total length of the diverging path (curve + frog rail)
|
||||
};
|
||||
|
||||
/// Lays a turnout forward from @p start — the switch start, tangent to the through
|
||||
/// track — turning toward its side until the heading has swung by the crossing
|
||||
/// angle, then running straight to the catalogue length. Never throws; returns
|
||||
/// `valid == false` when the parameters admit no geometry: a non-positive radius,
|
||||
/// or a curve whose fixed parts already overshoot the crossing angle before the
|
||||
/// closing arc.
|
||||
[[nodiscard]] TurnoutGeometry lay_turnout(const geometry::Pose& start,
|
||||
const Turnout& turnout);
|
||||
|
||||
} // namespace maj0sted::domain
|
||||
@@ -30,6 +30,10 @@ public:
|
||||
/// Perpendicular distance (>= 0) from @p other's start point to the
|
||||
/// (infinite) line carrying @p origin.
|
||||
static double perpendicular_distance(const Straight& origin, const Straight& other);
|
||||
|
||||
[[nodiscard]] static Straight project_onto_offset_line(const Straight& origin,
|
||||
double offset_m,
|
||||
const Straight& segment);
|
||||
};
|
||||
|
||||
} // namespace maj0sted::domain
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "maj0sted/web/solve.hpp" // WebPoint, WebPolyline
|
||||
#include "maj0sted/editor/solve.hpp" // PlanPoint, PlanPolyline
|
||||
|
||||
namespace maj0sted::web {
|
||||
namespace maj0sted::editor {
|
||||
|
||||
/// An anchored straight segment (two XY endpoints).
|
||||
struct StraightSpec {
|
||||
@@ -63,7 +63,7 @@ struct NiweletaSpec {
|
||||
};
|
||||
|
||||
struct NiweletaPolys {
|
||||
std::vector<WebPolyline> polylines;
|
||||
std::vector<PlanPolyline> polylines;
|
||||
/// Centreline segments after adjacent fits trim the input straights. Kept
|
||||
/// index-aligned with NiweletaSpec::straights for editor hit handles.
|
||||
std::vector<StraightSpec> rendered_straights;
|
||||
@@ -74,7 +74,7 @@ struct NiweletaPolys {
|
||||
std::vector<GapFit> applied_fits;
|
||||
/// The solved axis as one polyline, in order, with no duplicate join points.
|
||||
/// Lets a station along the niweleta be resolved to a pose (see pose_at).
|
||||
std::vector<WebPoint> centreline;
|
||||
std::vector<PlanPoint> centreline;
|
||||
};
|
||||
|
||||
/// Builds each niweleta, fits every requested gap, and returns the sampled plan
|
||||
@@ -98,6 +98,7 @@ struct Junction {
|
||||
int side{0}; ///< 0 = diverges left, 1 = diverges right
|
||||
bool facing{true}; ///< true opens toward increasing station, false back
|
||||
double crossing_n{9.0}; ///< crossing mark 1:n (skos) → leaving angle atan(1/n)
|
||||
double length{0.0}; ///< catalogue length (PR→KR along the through track); 0 = just the curve
|
||||
GapFit curve; ///< the internal diverging curve: arc / compound / basket
|
||||
int branch{-1}; ///< index of the branch niweleta, pinned to the frog
|
||||
};
|
||||
@@ -114,7 +115,7 @@ struct JunctionGeom {
|
||||
double tangent_back{0.0}; ///< theoretical tangent length after the curve
|
||||
double length{0.0}; ///< diverging curve length (switch point to frog), metres
|
||||
/// The diverging curve, as rails ready to draw.
|
||||
std::vector<WebPolyline> polylines;
|
||||
std::vector<PlanPolyline> polylines;
|
||||
};
|
||||
|
||||
/// A whole layout solved at once: the niwelety plus every switch. Returned by
|
||||
@@ -132,4 +133,4 @@ struct LayoutSolution {
|
||||
[[nodiscard]] LayoutSolution solve_layout(std::vector<NiweletaSpec> niwelety,
|
||||
const std::vector<Junction>& junctions);
|
||||
|
||||
} // namespace maj0sted::web
|
||||
} // namespace maj0sted::editor
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "maj0sted/web/solve.hpp" // WebPoint, WebPolyline
|
||||
#include "maj0sted/editor/solve.hpp" // PlanPoint, PlanPolyline
|
||||
|
||||
namespace maj0sted::web {
|
||||
namespace maj0sted::editor {
|
||||
|
||||
/// One element of an alignment "ribbon" (element chain), defined intrinsically.
|
||||
struct RibbonElement {
|
||||
@@ -27,6 +27,6 @@ struct RibbonRequest {
|
||||
};
|
||||
|
||||
/// Lays the ribbon out and returns one polyline per element, ready to draw.
|
||||
[[nodiscard]] std::vector<WebPolyline> solve_ribbon(const RibbonRequest& request);
|
||||
[[nodiscard]] std::vector<PlanPolyline> solve_ribbon(const RibbonRequest& request);
|
||||
|
||||
} // namespace maj0sted::web
|
||||
} // namespace maj0sted::editor
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace maj0sted::web {
|
||||
namespace maj0sted::editor {
|
||||
|
||||
/// A request from the GUI: three draggable vertices (entry straight A->B, exit
|
||||
/// straight B->C) plus the fit parameters. Plain doubles so it maps trivially
|
||||
/// onto a JS object / WASM boundary. This layer is pure C++ — the emscripten
|
||||
/// bindings are a thin wrapper around it, and it is unit-tested natively.
|
||||
/// straight B->C) plus the fit parameters. Plain doubles, a flat DTO across the
|
||||
/// boundary between the editor UI and this solver.
|
||||
struct SolveRequest {
|
||||
double ax{0.0}, ay{0.0}; ///< vertex A (entry start)
|
||||
double bx{0.0}, by{0.0}; ///< vertex B (corner: entry end = exit start)
|
||||
@@ -28,13 +27,13 @@ struct SolveRequest {
|
||||
};
|
||||
|
||||
/// A point in the CRS.
|
||||
struct WebPoint {
|
||||
struct PlanPoint {
|
||||
double x{0.0};
|
||||
double y{0.0};
|
||||
};
|
||||
|
||||
/// One polyline; @c kind is render::ElementKind (0 straight, 1 arc, 2 transition).
|
||||
struct WebPolyline {
|
||||
struct PlanPolyline {
|
||||
int kind{0};
|
||||
/// Logical owner used by map hit-testing. Exactly one is non-negative.
|
||||
int straight_index{-1};
|
||||
@@ -45,12 +44,12 @@ struct WebPolyline {
|
||||
/// Zero denotes an infinite radius (straight end of a transition).
|
||||
double radius_start{0.0};
|
||||
double radius_end{0.0};
|
||||
std::vector<WebPoint> points;
|
||||
std::vector<PlanPoint> points;
|
||||
};
|
||||
|
||||
/// Builds the niweleta, runs the requested fit (falling back to the bare
|
||||
/// straights if the parameters do not admit a fit) and returns the sampled plan
|
||||
/// as polylines ready to draw.
|
||||
[[nodiscard]] std::vector<WebPolyline> solve_scene(const SolveRequest& request);
|
||||
[[nodiscard]] std::vector<PlanPolyline> solve_scene(const SolveRequest& request);
|
||||
|
||||
} // namespace maj0sted::web
|
||||
} // namespace maj0sted::editor
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace maj0sted::web {
|
||||
namespace maj0sted::editor {
|
||||
|
||||
/// A stable tile in the EPSG:2180 tiling pyramid. Tiles are addressed by their
|
||||
/// zoom level and integer column/row, so the same ground square always maps to
|
||||
@@ -39,42 +39,43 @@ struct TileBBox {
|
||||
double max_y{0.0};
|
||||
};
|
||||
|
||||
/// The tiling scheme. A pure, static value type defining a single fixed square
|
||||
/// grid of 100 m × 100 m ground cells over the EPSG:2180 plane — the same grid
|
||||
/// at every zoom, *not* a per-zoom pyramid. Each cell has a deterministic ground
|
||||
/// bounding box, so it is cached once and reused across all pans and zooms.
|
||||
/// Nothing here touches the network — it is trivially unit testable natively.
|
||||
///
|
||||
/// The zoom parameters on the methods below are ignored; they are kept only so
|
||||
/// the host boundary (bindings/JS) stays unchanged.
|
||||
/// The tiling scheme. A pure, static value type defining a square grid over the
|
||||
/// EPSG:2180 plane. The default grid is fixed 100 m × 100 m cells (key.zoom =
|
||||
/// kLevel). Coarser overview grids encode the cell size in metres in
|
||||
/// @c TileKey::zoom when that value is >= 100 (e.g. zoom 1000 → 1 km cells for
|
||||
/// topo underlays). Nothing here touches the network.
|
||||
class TileGrid {
|
||||
public:
|
||||
static constexpr int kTilePixels = 1024; ///< pixels per cell edge (GetMap WIDTH/HEIGHT)
|
||||
static constexpr double kOriginX = 0.0; ///< easting of cell (0,0)'s left edge
|
||||
static constexpr double kOriginY = 0.0; ///< northing of cell (0,0)'s bottom edge
|
||||
/// Fixed cache cell size: every tile is a 100 m × 100 m ground square.
|
||||
/// Default cache cell size: 100 m × 100 m ground square.
|
||||
static constexpr double kCellMetres = 100.0;
|
||||
/// The single grid level stored in every TileKey (there is only one grid).
|
||||
/// Default grid level stored in TileKey::zoom for the 100 m grid.
|
||||
static constexpr int kLevel = 0;
|
||||
/// Zoom values at or above this are treated as the cell edge in metres.
|
||||
static constexpr int kCellZoomMin = 100;
|
||||
|
||||
/// Ground resolution (metres per pixel) of a cell. Constant (zoom ignored).
|
||||
/// Cell edge in metres for @p key (100 m default, or key.zoom when coarse).
|
||||
[[nodiscard]] static double cell_metres(const TileKey& key) noexcept;
|
||||
|
||||
/// Ground resolution (metres per pixel) of a cell.
|
||||
[[nodiscard]] static double resolution(int zoom = kLevel) noexcept;
|
||||
|
||||
/// Edge length of a cell in metres — always kCellMetres (zoom ignored).
|
||||
/// Edge length of a cell in metres for the given zoom/cell encoding.
|
||||
[[nodiscard]] static double tile_span(int zoom = kLevel) noexcept;
|
||||
|
||||
/// The 100 m cell whose ground square contains (@p x, @p y). Zoom ignored.
|
||||
/// The cell whose ground square contains (@p x, @p y).
|
||||
[[nodiscard]] static TileKey tile_at(double x, double y, int zoom = kLevel) noexcept;
|
||||
|
||||
/// The ground bounding box (EPSG:2180) of @p key.
|
||||
[[nodiscard]] static TileBBox bbox(const TileKey& key) noexcept;
|
||||
|
||||
/// The grid level for a target resolution. Always kLevel — the grid has a
|
||||
/// single fixed 100 m level. Kept for boundary compatibility.
|
||||
/// The grid level for a target resolution. Always kLevel for the fine grid.
|
||||
[[nodiscard]] static int zoom_for_resolution(double metres_per_pixel) noexcept;
|
||||
|
||||
/// Every 100 m cell whose ground square intersects @p view, capped at
|
||||
/// @p max_tiles to guard against absurd requests. Zoom ignored.
|
||||
/// Every cell whose ground square intersects @p view, capped at @p max_tiles.
|
||||
/// Pass a coarse cell size (e.g. 1000) as @p zoom to get a 1 km overview grid.
|
||||
[[nodiscard]] static std::vector<TileKey> tiles_for_view(const TileBBox& view,
|
||||
int zoom = kLevel,
|
||||
int max_tiles = 64);
|
||||
@@ -114,10 +115,9 @@ struct TileImage {
|
||||
};
|
||||
|
||||
/// Owns the tile grid, the tile cache and the WMS fetch. This is the single
|
||||
/// place that decides which tile is needed, whether it is already cached, and —
|
||||
/// on a miss — issues the network GetMap request itself. Under Emscripten the
|
||||
/// fetch uses the Emscripten Fetch API; natively (and in tests) a fetcher can be
|
||||
/// injected, so the tiling/caching logic is exercised without a real network.
|
||||
/// place that decides which tile is needed and whether it is already cached. The
|
||||
/// download itself is the host's: it injects a Fetcher, so the tiling and caching
|
||||
/// logic here stays transport-free and is exercised in tests without a network.
|
||||
class TileService {
|
||||
public:
|
||||
/// Called when a fetch finishes: (success, bytes, content_type).
|
||||
@@ -131,9 +131,8 @@ public:
|
||||
[[nodiscard]] const WmsConfig& config() const noexcept { return cfg_; }
|
||||
void set_config(WmsConfig cfg) { cfg_ = std::move(cfg); }
|
||||
|
||||
/// Overrides the network backend. When set it is used on both native and
|
||||
/// Emscripten builds; when unset, Emscripten builds fall back to
|
||||
/// emscripten_fetch and native builds mark the tile Failed.
|
||||
/// Sets the transport. When unset, a requested tile fails at once (there is
|
||||
/// no built-in downloader — the host owns that).
|
||||
void set_fetcher(Fetcher fetcher) { fetcher_ = std::move(fetcher); }
|
||||
|
||||
/// Notified (with the tile's key) whenever a tile transitions to Ready or
|
||||
@@ -161,20 +160,17 @@ public:
|
||||
|
||||
/// Finalises an in-flight fetch: on success stores the bytes (Ready), on
|
||||
/// failure marks the tile Failed, then fires the on_ready callback. Public so
|
||||
/// the Emscripten fetch glue (which needs free C callbacks) can delegate here.
|
||||
/// the host's fetcher callback can hand the result back here.
|
||||
void complete_fetch(const TileKey& key, bool ok, std::vector<std::uint8_t> bytes,
|
||||
std::string content_type);
|
||||
|
||||
/// Re-issues the fetch for @p key. Public so the Emscripten async-retry glue
|
||||
/// (a free C callback) can delegate here.
|
||||
/// Re-issues the fetch for @p key.
|
||||
void retry_now(const TileKey& key);
|
||||
|
||||
private:
|
||||
void begin_fetch(const TileKey& key);
|
||||
/// Re-issues a fetch for @p key after a failure — the service retries up to
|
||||
/// kMaxRetries times, then marks the tile Failed. Under Emscripten the retry
|
||||
/// is deferred asynchronously (after a short delay) so it never blocks or
|
||||
/// recurses; with an injected fetcher it re-issues immediately.
|
||||
/// kMaxRetries times, then marks the tile Failed. The fetcher owns the timing.
|
||||
void schedule_retry(const TileKey& key);
|
||||
|
||||
WmsConfig cfg_;
|
||||
@@ -183,4 +179,4 @@ private:
|
||||
std::function<void(TileKey)> on_ready_;
|
||||
};
|
||||
|
||||
} // namespace maj0sted::web
|
||||
} // namespace maj0sted::editor
|
||||
33
maj0sted/include/maj0sted/io/scn_export.hpp
Normal file
33
maj0sted/include/maj0sted/io/scn_export.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "maj0sted/editor/editor.hpp"
|
||||
|
||||
namespace maj0sted::io {
|
||||
|
||||
struct ScnExportOptions {
|
||||
double origin_east{0.0};
|
||||
double origin_north{0.0};
|
||||
double rail_y{0.2};
|
||||
double max_arc_angle{1.5707963267948966};
|
||||
};
|
||||
|
||||
struct ScnExportResult {
|
||||
int tracks{0};
|
||||
std::string first_track_name;
|
||||
double origin_east{0.0};
|
||||
double origin_north{0.0};
|
||||
};
|
||||
|
||||
[[nodiscard]] ScnExportResult export_scn(
|
||||
const std::vector<maj0sted::editor::NiweletaPolys>& solved,
|
||||
const ScnExportOptions& options, std::ostream& out);
|
||||
|
||||
[[nodiscard]] ScnExportOptions resolve_scn_origin(
|
||||
const std::vector<maj0sted::editor::NiweletaPolys>& solved,
|
||||
ScnExportOptions options);
|
||||
|
||||
} // namespace maj0sted::io
|
||||
Reference in New Issue
Block a user