/* 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/. */ #pragma once #include #include #include #include #include #include "editor/editorAlignment.hpp" #include "scene/scenelayers.h" class TTrack; // horizontal alignments designed in the track editor, kept in the scenery files as "//$h" comment lines: the design (its // vertices) and the elements it makes, so the tracks laid by it are known for straights, transition curves and arcs namespace alignment_store { // an element as the file gives it: radii signed with the turn, 0 for no curvature struct stored_element { std::string kind; // straight, transition, arc int vertex{-1}; double chainage{0.0}; double length{0.0}; double radius_start{0.0}; double radius_end{0.0}; double cant{0.0}; }; stored_element describe(alignment::element const &Element); struct record { scene::layer_handle layer{null_handle}; std::string source{"designed"}; double origin{0.0}; // chainage of the start, m alignment::design design; alignment::result result; // made of the design std::vector elements; // as written in the file bool consistent{true}; // the design makes the elements written in the file double fit{0.0}; glm::dvec2 low{0.0}; glm::dvec2 high{0.0}; std::vector samples; // the points clicked when the line was laid, its curves fitted to them, so they can be fitted again std::vector clicks; // the stretch of its line the design is kept for, chainages from its start: all of it, unless tracks along it were deleted and // the design was cut down to the ones left double from{0.0}; double to{-1.0}; // below 0: to the end of the line double kept_to() const { return to < 0.0 ? result.length : to; } bool whole() const { return from <= 1e-6 && (to < 0.0 || to >= result.length - 1e-6); } }; struct hit { int record{-1}; int element{-1}; double chainage{0.0}; // from the start of the record double offset{0.0}; // sideways from its line }; // the designed vertex a curve made of the tracks follows: its parameters in the direction of the tracks struct designed_vertex { int record{-1}; int vertex{-1}; alignment::vertex shape; bool reversed{false}; }; double constexpr tolerance{0.02}; void reset(); void load(); std::vector const &records(); std::optional at(glm::dvec3 const &Point, double const Reach = tolerance); // the track lies along a stored alignment, its middle is the hit std::optional on_track(TTrack const &Track, double const Reach = tolerance); // the vertex the tracks follow, if they all lie along one stored alignment and the curve elements under them belong to one vertex std::optional vertex_of(std::vector> const &Run); // stored alignment with these ends, either way; none cut down to a part of its line int find(glm::dvec3 const &Start, glm::dvec3 const &End, bool &Reversed); // the ends of the stretch of its line the record is kept for glm::dvec3 kept_start(record const &Record); glm::dvec3 kept_end(record const &Record); // the stored alignments the tracks deleted lay along cut down to the stretches of their line other tracks still lie along, a design // with none left forgotten: the part of a line with no track is no part of its design any more. Called before the deletion goes into // the undo history, which takes the records along. The count of the designs cut down or forgotten std::size_t trim(std::vector const &Removed); // stored alignment near the tracks, whose line they no longer follow; Departure receives the largest distance int departed(std::vector const &Tracks, double &Departure); // keeps the design in the file of the layer, in place of the one with the same ends; with no points clicked given it keeps the // ones of the design it takes the place of int store(alignment::design const &Design, alignment::result const &Result, double const Origin, scene::layer_handle const Layer, std::string const &Source = "designed", double const Fit = 0.0, std::vector const &Clicks = {}); // the points clicked when the lines were laid, kept with them, which lie by the line within the reach, between its ends std::vector clicks_along(alignment::result const &Result, double const Reach); bool follows(alignment::result const &Result, std::vector const &Tracks); double deviation(alignment::result const &Result, std::vector const &Tracks, TTrack *&Worst); std::optional chainage_on(alignment::result const &Result, glm::dvec3 const &Point); void forget(int const Index); // the point on the line of the stored alignment, if it lies by it within the reach std::optional on_record(int const Index, glm::dvec3 const &Point, double const Reach); // cant of the design at the chainage, mm double cant_at(int const Index, double const Chainage); // the stored alignment moved and turned in the plan the way the point and the direction were void transform(int const Index, glm::dvec3 const &From, glm::dvec2 const &Fromdirection, glm::dvec3 const &To, glm::dvec2 const &Todirection); // km of the point on the stored alignments, if it lies on one std::optional chainage_at(glm::dvec3 const &Point); // the records as they were before the changes made since the last call, if there were any; the current ones become the base std::optional> take_changes(); // the current records become the base, the changes made so far aren't a part of the undo history void settle(); // puts the records back as they were, for undo and redo void restore(std::vector Records); // layer the editor keeps the records of the track in: its own, unless it's a terrain file: a .txtf, whose binary version (.btf) // the editor doesn't read the records from, or a _ter.scm, which isn't written back while the scenery has its .sbt scene::layer_handle layer_of(TTrack const &Track); } // namespace alignment_store