17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-08 22:07:20 +01:00

Sieć trakcyjna: kotwienia, kotwienie środkowe, parasole i wysięgniki rozstawione, konsole 4890/4690

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

- kotwienia ciężarowe i stałe (0404/0405, przewody zakotwione osobno, sieci bez własnych danych: network <symbol> as <kod>)
- kotwienie środkowe 0406/0408/0418/0416: lina, V i zaciski na linie nośnej liczonej jak przęsło, obejma 4160 na teownikach
- parasole i wysięgniki rozstawione na konsolach 4890, wysięgi pomocnicze 0167 na belkach 4690, trzeci wysięgnik w osi słupa,
  lina nośna z innego wysięgnika (messenger_from)
- przęsła w nietypowych sytuacjach nie przechodzą na stary wygląd (bez Y, bez wieszaków, lina nad przewodem)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GfTogWDsfCE8RGFGvm2eyp
This commit is contained in:
Claude
2026-10-26 01:12:06 +01:00
parent f30fefd91c
commit 619f048f31
18 changed files with 4237 additions and 285 deletions

View File

@@ -99,7 +99,10 @@ void type_registry::load_tables() {
double mass { 0.0 }, diameter { 0.0 };
stream >> mass >> diameter;
if( stream.fail() || mass <= 0.0 ) { report( "Catenary: bad wire entry in \"" + filename + "\" (line " + std::to_string( linenumber ) + ")" ); continue; }
m_wires[ key ] = { mass, diameter * 0.001 };
// dalej opcjonalnie: przekrój mm² i moduł sprężystości GPa
double area { 0.0 }, modulus { 0.0 };
if( stream >> area ) { stream >> modulus; }
m_wires[ key ] = { mass, diameter * 0.001, std::max( 0.0, area ) * 1e-6, std::max( 0.0, modulus ) * 1e9 };
}
else if( kind == "spacing" ) {
int span { 0 };
@@ -267,25 +270,34 @@ bool solve_span_points( network_definition const &Definition, std::vector<double
input.y_at_start = Ystart;
input.y_at_end = Yend;
span_result result;
try {
// bez rozstawu wieszaków: odcinek do kotwienia, same liny
result = ( Hangergaps.empty() ?
solve_free_span( type, length, input.height_start, input.height_end ) :
solve_span( type, input, 4.0 ) );
}
catch( std::exception const &exception ) {
Error = exception.what();
return false;
}
// lina poniżej przewodu jezdnego: przęsło za długie albo za mała wysokość konstrukcyjna dla tego typu sieci
for( auto const *line : { &result.messenger, &result.y_start, &result.y_end } ) {
for( auto const &point : *line ) {
if( point.y - ( type.messenger_count > 1 ? type.messenger_stack : 0.0 ) < -0.01 ) {
Error = "messenger wire would hang below the contact wire (span too long or suspension too low for this network type)";
return false;
auto solved { false };
// nietypowe przęsła (niska wysokość konstrukcyjna jednego końca, naciąg liny obniżony brakującymi ciężarami poniżej naciągu
// linki Y): zamiast rysowania po staremu najpierw bez linek Y, potem jako odcinek bez wieszaków
for( int attempt = 0; attempt < 3 && false == solved; ++attempt ) {
try {
if( attempt == 2 || Hangergaps.empty() ) { result = solve_free_span( type, length, input.height_start, input.height_end ); }
else {
if( attempt == 1 ) { input.y_at_start = input.y_at_end = false; }
result = solve_span( type, input, 4.0 );
}
solved = true;
}
catch( std::exception const &exception ) {
Error = exception.what();
}
}
if( false == solved ) { return false; }
// lina poniżej przewodu jezdnego (przęsło za długie albo za mała wysokość konstrukcyjna dla tego typu sieci): podciągnięta
// nad przewód, wieszaki skrócone - przęsło wygląda dziwnie, ale się rysuje
// (końce zostają tam, gdzie są punkty przęsła: najniżej na prostej między nimi)
auto const lowest { ( type.messenger_count > 1 ? type.messenger_stack : 0.0 ) + 0.02 };
for( auto *line : { &result.messenger, &result.y_start, &result.y_end } ) {
for( auto &point : *line ) {
auto const chord { input.height_start + ( input.height_end - input.height_start ) * std::clamp( point.x / length, 0.0, 1.0 ) };
point.y = std::max( point.y, std::min( lowest, chord ) );
}
}
for( auto &hanger : result.hangers ) { hanger.length = std::max( hanger.length, 0.0 ); }
Solution.length = length;
Solution.result = std::move( result );
return true;
@@ -435,10 +447,27 @@ void build_geometry( network_definition const &Definition, span_solution const &
if( type.messenger_count > 1 ) {
std::vector<vec3> middle;
if( false == start.empty() ) { middle.push_back( start.back() ); }
// końce dolnej liny podane osobno (kotwienie): przesunięcie rozłożone liniowo wzdłuż przęsła
vec3 shiftstart { 0.0, 0.0, 0.0 }, shiftend { 0.0, 0.0, 0.0 };
if( Points.messenger2_start_set && false == result.messenger.empty() ) {
auto const from { rope( result.messenger.front().x, result.messenger.front().y - type.messenger_stack ) };
shiftstart = vec3 { Points.messenger2_start.x - from.x, Points.messenger2_start.y - from.y, Points.messenger2_start.z - from.z };
}
if( Points.messenger2_end_set && false == result.messenger.empty() ) {
auto const to { rope( result.messenger.back().x, result.messenger.back().y - type.messenger_stack ) };
shiftend = vec3 { Points.messenger2_end.x - to.x, Points.messenger2_end.y - to.y, Points.messenger2_end.z - to.z };
}
for( auto const &point : result.messenger ) {
auto const instart { reachstart > 0.0 && point.x < reachstart + 1e-6 };
auto const inend { reachend > 0.0 && point.x > length - reachend - 1e-6 };
if( false == instart && false == inend ) { middle.push_back( rope( point.x, point.y - type.messenger_stack ) ); }
if( false == instart && false == inend ) {
auto at { rope( point.x, point.y - type.messenger_stack ) };
auto const t { length > 1e-9 ? point.x / length : 0.0 };
at.x += shiftstart.x * ( 1.0 - t ) + shiftend.x * t;
at.y += shiftstart.y * ( 1.0 - t ) + shiftend.y * t;
at.z += shiftstart.z * ( 1.0 - t ) + shiftend.z * t;
middle.push_back( at );
}
}
if( false == end.empty() ) { middle.push_back( end.front() ); }
polyline( middle, element_kind::messenger );