17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-05 12:09:02 +01:00

Sieć trakcyjna: przęsła wg typów sieci, wysięgniki z katalogu, bramki, kotwienia i edytor sieci

Sam kod exe z gałęzi siec-trakcyjna (bez testów, notatek i danych z tests/catenary).
Dane (data/traction_*.txt) leżą poza repozytorium.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Tqn7T8D1Gx3ptKtZgNtX5
This commit is contained in:
Claude
2026-10-23 23:15:00 +02:00
parent b4b1e6c32f
commit f30fefd91c
45 changed files with 12595 additions and 24 deletions

164
world/catenary_network.h Normal file
View File

@@ -0,0 +1,164 @@
// Sieć trakcyjna: katalog typów sieci czytany z plików danych oraz geometria przęsła liczona solverem.
// Kod niezależny od reszty symulatora (C++17, tylko biblioteka standardowa), żeby dało się go testować osobno.
#pragma once
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "world/catenary_solver.h"
namespace catenary {
// przewód albo lina z tabeli przewodów
struct wire_data {
double mass { 0.0 }; // kg/m
double diameter { 0.0 }; // m
};
// pełny opis typu sieci: dane dla solvera i dane potrzebne tylko do rysowania
struct network_definition {
network_type type;
std::string hanger_table; // nazwa tablicy rozstawu wieszaków
double contact_spacing { 0.0 }; // m, rozstaw dwóch przewodów jezdnych; 0 = wziąć ze scenerii
wire_data contact_wire;
wire_data messenger_wire;
wire_data y_wire;
wire_data hanger_wire; // linka wieszaków
double y_plan_offset { 0.5 }; // przebieg linki Y w planie na łuku: 0 = przez oś podwieszenia, 1 = prosto od zacisku do zacisku
};
// katalog typów sieci. Pliki są czytane przy pierwszym użyciu; każdy błąd zgłaszany jest tylko raz
class type_registry {
public:
// katalog z plikami traction_<symbol>.txt i traction_tables.txt
void directory( std::string const &Path );
// odbiorca komunikatów o błędach w danych
std::function<void( std::string const & )> on_error;
// zwraca opis typu albo nullptr, gdy pliku nie ma lub jest niekompletny. Wskaźnik pozostaje ważny do końca programu
network_definition const *find( std::string const &Symbol );
// odstępy wieszaków dla przęsła o podanej rozpiętości: oś podwieszenia–1, 1–2, …, ostatni–oś podwieszenia.
// rozpiętość niecałkowita: wiersz najbliższej całkowitej z rozciągniętymi środkowymi odstępami;
// rozpiętość spoza tablicy: odstępy wyznaczone regułą z odstępem skrajnym i największym odstępem z najbliższego wiersza
std::vector<double> hanger_gaps( std::string const &Table, double Length );
private:
void load_tables();
std::unique_ptr<network_definition> load_type( std::string const &Symbol );
void report( std::string const &Message );
std::mutex m_mutex;
std::string m_directory { "data/" };
bool m_tablesloaded { false };
std::map<std::string, wire_data> m_wires;
std::map<std::string, std::map<int, std::vector<double>>> m_spacing;
std::map<std::string, std::unique_ptr<network_definition>> m_types; // nullptr = typ błędny, już zgłoszony
std::map<std::string, bool> m_reported;
};
// wspólny katalog typów
type_registry &types();
struct vec3 { double x, y, z; };
// położenie przęsła w scenerii: końce przewodu jezdnego (osi sieci) i końce liny nośnej
struct span_points {
vec3 contact_start, contact_end;
vec3 messenger_start, messenger_end;
};
// policzone przęsło
struct span_solution {
double length { 0.0 }; // m, rozpiętość w poziomie
span_result result;
};
// liczy przęsło. Ystart, Yend: czy przy danym podwieszeniu jest linka Y (o ile typ ją przewiduje dla tej rozpiętości).
// pusty Hangergaps oznacza odcinek bez wieszaków (do kotwienia albo urządzenia naprężającego): same liny pod własnym ciężarem
// zwraca false i opis w Error, gdy przęsła nie da się policzyć
bool solve_span_points( network_definition const &Definition, std::vector<double> const &Hangergaps, span_points const &Points,
bool Ystart, bool Yend, span_solution &Solution, std::string &Error );
// uzgadnia linkę Y przy jednym podwieszeniu z połową linki z sąsiedniego przęsła (patrz join_y w solverze)
void join_y( network_definition const &Definition, span_solution &Solution, bool Atend, y_half const &Neighbour );
// połowa linki Y w układzie sceny: dane do wyznaczenia przebiegu linki w planie razem z sąsiednim przęsłem
struct y_side {
bool valid { false }; // false = przy tym podwieszeniu nie ma linki Y
double reach { 0.0 }; // m, odległość zacisku od osi podwieszenia
vec3 junction; // zacisk na linie nośnej
vec3 axis; // punkt liny nośnej w osi podwieszenia
};
// przebieg linki Y w planie po jednej stronie podwieszenia: łagodny łuk od zacisku do zacisku
struct y_plan {
bool valid { false }; // false = linka w planie pod cięciwą liny nośnej
double reach { 0.0 }; // m, odległość zacisku w tym przęśle od osi podwieszenia
double total { 0.0 }; // m, odległość między zaciskami mierzona wzdłuż liny nośnej
vec3 start, control, end; // łuk: zacisk w tym przęśle, punkt kierujący, zacisk w sąsiednim (liczą się x i z)
// punkt linki w odległości Distance od osi podwieszenia, w głąb tego przęsła
vec3 point( double Distance ) const;
};
// zbiera dane połowy linki Y z policzonego przęsła
y_side make_y_side( span_solution const &Solution, span_points const &Points, bool Atend );
// wyznacza przebieg linki Y w planie. Na łuku lina nośna łamie się w osi podwieszenia, a linka Y, zaciśnięta na linie
// po obu stronach, przechodzi obok tego załomu łagodnym łukiem. O tym, jak daleko od załomu, decyduje wpis typu
// y_plan_offset: 0 = linka przechodzi przez oś podwieszenia, 1 = biegnie prosto od zacisku do zacisku.
// Obie strony liczone z tych samych danych dają ten sam przebieg
y_plan solve_y_plan( network_definition const &Definition, y_side const &Mine, y_side const &Other );
// elementy przęsła do narysowania
enum class element_kind { contact, messenger, y_rope, hanger, link };
enum class fitting_kind { rope_clamp, wire_clamp, y_clamp, link_clamp };
// odcinek przewodu, liny albo linki
struct span_element {
vec3 from, to;
element_kind kind;
};
// miejsce połączenia: uchwyt wieszaka na linie i na przewodzie, zacisk linki Y na linie nośnej, zacisk łączący dwie liny
struct span_fitting {
vec3 position;
vec3 along; // kierunek przewodu w tym miejscu, poziomy, jednostkowy
fitting_kind kind;
};
struct span_geometry {
std::vector<span_element> elements;
std::vector<span_fitting> fittings;
};
// zbiera elementy przęsła w układzie sceny.
// Fallbackoffset: połowa rozstawu przewodów jezdnych ze scenerii, używana gdy typ nie podaje rozstawu.
// Ystart, Yend: przebieg linek Y w planie; domyślnie pod cięciwą liny nośnej
void build_geometry( network_definition const &Definition, span_solution const &Solution, span_points const &Points,
double Fallbackoffset, span_geometry &Output, y_plan const &Ystart = {}, y_plan const &Yend = {} );
// odcinki do narysowania przęsła liniami: kolejne pary punktów w Output
void build_lines( network_definition const &Definition, span_solution const &Solution, span_points const &Points,
double Fallbackoffset, std::vector<vec3> &Output, y_plan const &Ystart = {}, y_plan const &Yend = {} );
// wierzchołek bryły: położenie i wektor normalny do cieniowania
struct solid_vertex {
vec3 position;
vec3 normal;
};
// bryły do oglądania z bliska: przewody i liny jako graniastosłupy o średnicach z tabeli przewodów (Wires), w miejscach
// połączeń prostopadłościany zastępcze, do zastąpienia modelami uchwytów (Fittings). Kolejne trójki wierzchołków to trójkąty.
// Przewody i osprzęt są osobno, bo rysowane są z różnych materiałów
void build_solid( network_definition const &Definition, span_geometry const &Geometry, std::vector<solid_vertex> &Wires, std::vector<solid_vertex> &Fittings );
// średnica przewodu: z tabeli, a gdy jej tam nie ma, oszacowana z masy jak dla linki miedzianej
double wire_diameter( wire_data const &Wire );
// to samo w jednym kroku dla przęsła liczonego osobno, z linką Y przy obu podwieszeniach
bool build_span_lines( network_definition const &Definition, std::vector<double> const &Hangergaps, span_points const &Points,
double Fallbackoffset, std::vector<vec3> &Output, std::string &Error );
} // namespace catenary