mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-27 01:09:48 +01:00
feat(rails): the wing rails of the frogs of the low section of the blades, as Zu1-60, where the timbers have slide chairs: from 1.5 m before the throat to their ends the foot raised as much as the blades ride, the web shortened, the heads level with the rails beside, forged down to the plain rail along 0.5 m; a wing rail which is the stock rail of a blade too, as in the slips with the blades outside of the diamond, whole along its chairs; the fastening holding only rails raised as much moved up on a pad as wide as it, a raised rail on a fastening with others on a pad of its own
This commit is contained in:
@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "world/TrackRails.h"
|
||||
#include "world/TrackSleepers.h"
|
||||
#include "world/TrackBlend.h"
|
||||
#include "rendering/renderer.h"
|
||||
|
||||
@@ -381,6 +382,7 @@ struct rail_piece {
|
||||
bool walls { false };
|
||||
float lift { 0.f };
|
||||
float wallu { -1.f };
|
||||
knots::line rises;
|
||||
};
|
||||
|
||||
struct top_band {
|
||||
@@ -605,6 +607,8 @@ private:
|
||||
TSegment const &m_segment;
|
||||
double const m_length;
|
||||
double const m_guardoffset;
|
||||
double const m_rise; // of the feet of the wing rails of the low section
|
||||
glm::dvec2 const m_stock; // the stretch the rail is the stock rail of a blade along
|
||||
std::size_t m_topfirst;
|
||||
std::size_t m_toplast { 0 };
|
||||
std::vector<material_handle> m_tints;
|
||||
@@ -626,6 +630,8 @@ TTrack::rail_layer::rail_layer( TTrack &Track, rail_layout const &Layout, rail_d
|
||||
m_segment { path_segment( Track, Path ) },
|
||||
m_length { m_segment.GetLength() },
|
||||
m_guardoffset { -( flangeway + Drawing.size.head ) },
|
||||
m_rise { track_sleepers::wing_rise( Track ) },
|
||||
m_stock { track_sleepers::stock_stretch( Track, Path, Side ) },
|
||||
m_topfirst { Profile.size() } {
|
||||
// the running surface on top of the head is split along the edge of the wheel treads, the part of it out of their reach goes matte; the rest of the profile and the end faces are laid whole
|
||||
for( std::size_t j = 0; j < Profile.size(); ++j ) {
|
||||
@@ -791,6 +797,7 @@ void TTrack::rail_layer::lay_cuts( gfx::vertex_array const &Shape, std::vector<r
|
||||
// a piece carved between two cuts has the same lines at both
|
||||
auto const own { i < Cuts.size() && false == ( i > 0 && Cuts[ i - 1 ].carved && Cuts[ i ].carved ) };
|
||||
auto const pieceoffsets { part_offsets( i > 0 ? &Cuts[ i - 1 ] : nullptr, i < Cuts.size() ? &Cuts[ i ] : nullptr ) };
|
||||
auto const piecerises { part_rises( i > 0 ? &Cuts[ i - 1 ] : nullptr, i < Cuts.size() ? &Cuts[ i ] : nullptr, Wheels ? m_rise : 0.0, m_stock ) };
|
||||
// the limits of the head from both ends can overlap along a short piece, as the planed wing rail of one frog and the cut of the next: the tighter of them holds
|
||||
auto const pieceextents { own ? knots::bound( extents, Cuts[ i ].endextents, true ) : extents };
|
||||
auto const pieceinner { own ? knots::bound( inner, Cuts[ i ].endinner, false ) : inner };
|
||||
@@ -838,7 +845,8 @@ void TTrack::rail_layer::lay_cuts( gfx::vertex_array const &Shape, std::vector<r
|
||||
.capfrom = k == 1 && capstart,
|
||||
.capto = k + 1 == splits.size() && capend,
|
||||
.walls = false == Wheels,
|
||||
.wallu = Wallu };
|
||||
.wallu = Wallu,
|
||||
.rises = piecerises };
|
||||
if( Wheels && tread != nullptr && false == tread->edge.empty() && m_topfirst < m_toplast ) {
|
||||
treaded( whole, *tread, ends );
|
||||
}
|
||||
@@ -1270,6 +1278,10 @@ loft_span TTrack::rail_layer::span( rail_piece const &Piece, piece_ends const &E
|
||||
result.rampwidth = ( Piece.ramp.empty() ? 0.0 : Piece.fade );
|
||||
result.walls = Piece.walls;
|
||||
result.wallu = Piece.wallu;
|
||||
result.rises = Piece.rises;
|
||||
if( false == Piece.rises.empty() ) {
|
||||
result.head = { m_drawing.size.neck, m_drawing.size.crest };
|
||||
}
|
||||
if( std::abs( Piece.from - Ends.from ) < 1e-6 ) {
|
||||
result.fromend = Ends.fromend;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
@@ -49,6 +50,8 @@ double constexpr blade_gap { 0.0005 };
|
||||
double constexpr blade_lowered { 0.050 };
|
||||
double constexpr blade_spacing { 0.5 };
|
||||
double constexpr blade_runon_margin { 0.2 }; // how far short of the end of the plain track a blade running on into it ends
|
||||
double constexpr wing_low { 1.5 }; // how far before the throat the wing rails are of the low section of the blades, raised on their timbers as the blades
|
||||
double constexpr wing_forged { 0.5 }; // how long the end of a wing rail forged to the plain rail is, going down to it
|
||||
|
||||
// where the inner rails of the two paths of a switch cross, found from their gauge lines behind the blades
|
||||
struct switch_frog {
|
||||
@@ -175,6 +178,36 @@ inline knots::line part_offsets( rail_cut const *Before, rail_cut const *After )
|
||||
knots::sort( result );
|
||||
return result;
|
||||
}
|
||||
// how far the foot of a part of a rail between two cuts is raised, Rise along a wing rail of the low section: from wing_low before the throat on,
|
||||
// down to the plain rail past it along its forged end; the rail whole along Stock, the stock rail of a blade there
|
||||
inline knots::line part_rises( rail_cut const *Before, rail_cut const *After, double const Rise, glm::dvec2 const &Stock ) {
|
||||
|
||||
knots::line result;
|
||||
auto const going { Before != nullptr && Before->startkind == rail_end::point };
|
||||
auto const coming { After != nullptr && After->endkind == rail_end::point };
|
||||
if( Rise <= 0.0 || ( false == going && false == coming ) ) {
|
||||
return result;
|
||||
}
|
||||
auto const lowto { going ? Before->startanchor + wing_low : 0.0 };
|
||||
auto const lowfrom { coming ? After->endanchor - wing_low : 0.0 };
|
||||
auto const through { going && coming && lowto + 2.0 * wing_forged >= lowfrom };
|
||||
auto const stock { Stock.y > Stock.x };
|
||||
// the share of the rise: whole along the low section, none along the stock rail, between along the forged ends
|
||||
auto const share = [&]( double const At ) {
|
||||
auto const low { through ? 1.0 : std::max(
|
||||
going ? std::clamp( ( lowto + wing_forged - At ) / wing_forged, 0.0, 1.0 ) : 0.0,
|
||||
coming ? std::clamp( ( At - lowfrom + wing_forged ) / wing_forged, 0.0, 1.0 ) : 0.0 ) };
|
||||
auto const whole { stock ? std::clamp( std::max( Stock.x - At, At - Stock.y ) / wing_forged, 0.0, 1.0 ) : 1.0 };
|
||||
return std::min( low, whole ); };
|
||||
std::array<double, 8> places { lowto, lowto + wing_forged, lowfrom - wing_forged, lowfrom, Stock.x - wing_forged, Stock.x, Stock.y, Stock.y + wing_forged };
|
||||
std::sort( places.begin(), places.end() );
|
||||
for( auto const at : places ) {
|
||||
if( result.empty() || at > result.back().x + 1e-6 ) {
|
||||
result.emplace_back( at, Rise * share( at ) );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
struct rail_tread {
|
||||
double from { 0.0 };
|
||||
double to { 0.0 };
|
||||
|
||||
@@ -717,7 +717,7 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
for( auto distance { std::ceil( Span.from / 0.5 ) * 0.5 }; distance < std::min( Span.to, m_dense ); distance += 0.5 ) {
|
||||
stations.push_back( distance );
|
||||
}
|
||||
for( auto const *line : { &Span.offsets, &Span.extents, &Span.inner, &Span.drops } ) {
|
||||
for( auto const *line : { &Span.offsets, &Span.extents, &Span.inner, &Span.drops, &Span.rises } ) {
|
||||
for( auto const &knot : *line ) {
|
||||
if( knot.x > Span.from && knot.x < Span.to ) {
|
||||
stations.push_back( knot.x );
|
||||
@@ -759,11 +759,11 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
for( auto const &point : ShapePoints ) {
|
||||
bottom = std::min( bottom, point.position.y );
|
||||
}
|
||||
auto const raised = [&]( float const Height ) {
|
||||
if( Span.rise <= 0.0 || Height >= Span.head.x || Span.head.x <= bottom ) {
|
||||
auto const raised = [&]( float const Height, double const Rise ) {
|
||||
if( Rise <= 0.0 || Height >= Span.head.x || Span.head.x <= bottom ) {
|
||||
return Height;
|
||||
}
|
||||
return static_cast<float>( Height + Span.rise * ( Span.head.x - Height ) / ( Span.head.x - bottom ) ); };
|
||||
return static_cast<float>( Height + Rise * ( Span.head.x - Height ) / ( Span.head.x - bottom ) ); };
|
||||
|
||||
auto const ring = [&]( double const Distance, double const Middle, std::vector<gfx::basic_vertex> &Ring, std::vector<float> &Wear ) {
|
||||
glm::dvec3 point;
|
||||
@@ -797,6 +797,7 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
}
|
||||
auto const worn { knots::sample( Span.ramp, Distance, -1e6 ) };
|
||||
auto const drop { knots::sample( Span.drops, Distance, 0.0 ) };
|
||||
auto const rise { Span.rises.empty() ? Span.rise : knots::sample( Span.rises, Distance, 0.0 ) };
|
||||
static loft_end const unshaped;
|
||||
auto const &shaped { Distance <= Span.from ? Span.fromend : Distance >= Span.to ? Span.toend : unshaped };
|
||||
auto const bend { shaped.bend };
|
||||
@@ -830,7 +831,7 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
// nothing of the profile between the limits there: the ring shrinks to one point, the step draws nothing
|
||||
auto const outside { std::clamp( 0.5 * ( std::min( extent, farthest ) + std::max( innerextent, nearest ) ), nearest, farthest ) };
|
||||
auto pt { parallel * static_cast<float>( Span.side * ( Span.halfwidth + outside + offset ) ) + position };
|
||||
pt.y += raised( ShapePoints.front().position.y ) + Span.lift;
|
||||
pt.y += raised( ShapePoints.front().position.y, rise ) + Span.lift;
|
||||
for( std::size_t j = 0; j < count; ++j ) {
|
||||
Ring.emplace_back( pt, glm::vec3{ 0.f, 1.f, 0.f }, glm::vec2{ ShapePoints[ j ].texture.x, 0.f } );
|
||||
Wear.push_back( 1.f );
|
||||
@@ -909,7 +910,7 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
if( drop > 0.0 && shape.position.y > Span.head.x && Span.head.y > Span.head.x ) {
|
||||
shape.position.y -= static_cast<float>( drop * ( shape.position.y - Span.head.x ) / ( Span.head.y - Span.head.x ) );
|
||||
}
|
||||
shape.position.y = raised( shape.position.y );
|
||||
shape.position.y = raised( shape.position.y, rise );
|
||||
auto pt { parallel * static_cast<float>( Span.side * ( Span.halfwidth + outside + offset ) ) + position + along * static_cast<float>( outside + offset ) };
|
||||
pt.y += shape.position.y + Span.lift;
|
||||
auto norm { shape.normal.x * parallel };
|
||||
|
||||
@@ -48,6 +48,7 @@ struct loft_span {
|
||||
knots::line drops;
|
||||
glm::dvec2 head { 0.0 };
|
||||
double rise { 0.0 }; // how far the foot of the profile is raised, the web below the head (head.x) shortened by as much
|
||||
knots::line rises; // along the span, in place of rise where given
|
||||
};
|
||||
|
||||
struct segment_data {
|
||||
|
||||
@@ -52,22 +52,17 @@ fastened_rails::fastened_rails( TTrack &Track ) {
|
||||
auto const middle { 0.5 * std::abs( track->fTrackWidth ) + size.web };
|
||||
auto const cut { track_rails::cut_rails( *track ) };
|
||||
auto const switched { track->eType == tt_Switch && track->SwitchExtension != nullptr };
|
||||
// the side of the blade of the path, and the stretch along it from the tip to the heel
|
||||
auto const rise { wing_rise( *track ) };
|
||||
// the side of the blade of the path
|
||||
auto const bladeside = [&]( int const Path ) {
|
||||
return ( track->SwitchExtension->RightSwitch == ( Path == 0 ) ? 1 : -1 ); };
|
||||
auto const bladestretch = [&]( int const Path ) {
|
||||
auto const &shape { track->blade( Path ) };
|
||||
return glm::dvec2 { shape.valid ? shape.tip : 0.0, track_rails::blade_length( *track, Path ) }; };
|
||||
// what the rail is along the path: a blade, the stock rail of a blade, checked
|
||||
auto const add = [&]( rail &&Line, int const Path, int const Side ) {
|
||||
if( switched ) {
|
||||
if( Side == bladeside( Path ) ) {
|
||||
Line.blade = { 0.0, bladestretch( Path ).y };
|
||||
}
|
||||
if( Side == bladeside( 1 - Path ) ) {
|
||||
auto const stretch { bladestretch( 1 - Path ) };
|
||||
Line.stock = { std::max( 0.0, stretch.x - chair_lead ), stretch.y };
|
||||
Line.blade = { 0.0, track_rails::blade_length( *track, Path ) };
|
||||
}
|
||||
Line.stock = stock_stretch( *track, Path, Side );
|
||||
}
|
||||
if( cut ) {
|
||||
for( auto const &check : track_rails::rail_checks( *track )[ Path ][ Side > 0 ? 1 : 0 ] ) {
|
||||
@@ -100,6 +95,7 @@ fastened_rails::fastened_rails( TTrack &Track ) {
|
||||
line.track = track;
|
||||
line.path = path;
|
||||
line.side = side;
|
||||
line.rises = track_rails::part_rises( before, after, rise, stock_stretch( *track, path, side ) );
|
||||
line.foot = size.web - size.low;
|
||||
line.low = glm::dvec2 { std::numeric_limits<double>::max() };
|
||||
line.high = glm::dvec2 { std::numeric_limits<double>::lowest() };
|
||||
@@ -159,11 +155,13 @@ std::vector<fastened_rails::hit> fastened_rails::rails_on( beam const &Beam ) co
|
||||
if( std::abs( height - glm::mix( Beam.from.y, Beam.to.y, u ) ) > level_tolerance ) {
|
||||
continue;
|
||||
}
|
||||
auto const distance { glm::mix( line.distances[ index - 1 ], line.distances[ index ], v ) };
|
||||
hits.push_back( {
|
||||
u * length,
|
||||
line.at( glm::mix( line.distances[ index - 1 ], line.distances[ index ], v ) ),
|
||||
line.at( distance ),
|
||||
glm::normalize( glm::mix( line.inward[ index - 1 ], line.inward[ index ], v ) ),
|
||||
line.foot } );
|
||||
line.foot,
|
||||
knots::sample( line.rises, distance, 0.0 ) } );
|
||||
}
|
||||
}
|
||||
std::sort( hits.begin(), hits.end(), []( hit const &Left, hit const &Right ) { return Left.at < Right.at; } );
|
||||
@@ -180,11 +178,14 @@ std::vector<fastened_rails::hit> fastened_rails::rails_on( beam const &Beam ) co
|
||||
for( std::size_t index = 0; index < hits.size(); ) {
|
||||
auto best { hits[ index ] };
|
||||
auto next { index + 1 };
|
||||
auto rise { best.rise };
|
||||
for( ; next < hits.size() && hits[ next ].at - hits[ next - 1 ].at < fastening_merge; ++next ) {
|
||||
if( rank( hits[ next ].kind ) > rank( best.kind ) ) {
|
||||
best = hits[ next ];
|
||||
}
|
||||
rise = std::max( rise, hits[ next ].rise );
|
||||
}
|
||||
best.rise = rise;
|
||||
if( best.kind != role::blade ) {
|
||||
rails.push_back( best );
|
||||
}
|
||||
@@ -324,6 +325,7 @@ std::vector<fastening> fastened_rails::on( beam const &Beam, beam_model const &M
|
||||
}
|
||||
}
|
||||
fit( result, Beam, Model );
|
||||
lift( result, rails, Beam, Model );
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -618,6 +620,81 @@ void fastened_rails::fit( std::vector<fastening> &Fastenings, beam const &Beam,
|
||||
Fastenings = std::move( fitted );
|
||||
}
|
||||
|
||||
void fastened_rails::lift( std::vector<fastening> &Fastenings, std::vector<hit> const &Rails, beam const &Beam, beam_model const &Model ) {
|
||||
|
||||
if( std::none_of( Rails.begin(), Rails.end(), []( hit const &Rail ) { return Rail.rise > 0.0; } ) ) {
|
||||
return;
|
||||
}
|
||||
auto const start { plan( Beam.from ) };
|
||||
auto const axis { glm::normalize( plan( Beam.to - Beam.from ) ) };
|
||||
auto const padpart { Model.parts[ part_slide ] != nullptr ? part_slide : part_plate };
|
||||
auto const &padspan { Model.spans[ padpart ] };
|
||||
auto const &padheights { Model.heights[ padpart ] };
|
||||
// a pad on the timber under the fastening, along its across from Low to High, up from Bottom to Top in the model
|
||||
auto const pad = [&]( fastening const &Over, double const Low, double const High, float const Bottom, float const Top ) {
|
||||
fastening result { padpart, Over.point, Over.across };
|
||||
result.scale = static_cast<float>( ( High - Low ) / ( padspan.y - padspan.x ) );
|
||||
result.shift = static_cast<float>( Low - result.scale * padspan.x );
|
||||
result.lift = Bottom - padheights.x;
|
||||
result.height = ( Top - Bottom ) / std::max( 0.001f, padheights.y - padheights.x );
|
||||
result.pad = true;
|
||||
return result; };
|
||||
// where along the timber the fastening reaches, from and to
|
||||
auto const footprint = [&]( fastening const &Fastening ) {
|
||||
auto const at { glm::dot( plan( Fastening.point ) - start, axis ) };
|
||||
auto const turn { glm::dot( Fastening.across, axis ) };
|
||||
auto const &span { Model.spans[ Fastening.part ] };
|
||||
auto const a { at + turn * Fastening.placed( span.x, Fastening.scale ) };
|
||||
auto const b { at + turn * Fastening.placed( span.y, Fastening.scale ) };
|
||||
return glm::dvec2 { std::min( a, b ), std::max( a, b ) }; };
|
||||
auto const holds = [&]( fastening const &Fastening, hit const &Rail ) {
|
||||
auto const reach { footprint( Fastening ) };
|
||||
return Fastening.part != part_chair && Rail.at >= reach.x && Rail.at <= reach.y; };
|
||||
std::vector<fastening> pads;
|
||||
std::vector<bool> lifted( Fastenings.size(), false );
|
||||
for( std::size_t index = 0; index < Rails.size(); ++index ) {
|
||||
auto const &rail { Rails[ index ] };
|
||||
if( rail.rise < pad_least ) {
|
||||
continue;
|
||||
}
|
||||
auto const under { std::find_if( Fastenings.begin(), Fastenings.end(), [&]( fastening const &Fastening ) { return holds( Fastening, rail ); } ) };
|
||||
if( under == Fastenings.end() ) {
|
||||
continue;
|
||||
}
|
||||
auto const which { static_cast<std::size_t>( under - Fastenings.begin() ) };
|
||||
if( lifted[ which ] ) {
|
||||
continue;
|
||||
}
|
||||
auto const alike { std::all_of( Rails.begin(), Rails.end(), [&]( hit const &Other ) {
|
||||
return false == holds( *under, Other ) || std::abs( Other.rise - rail.rise ) < pad_least; } ) };
|
||||
if( alike ) {
|
||||
// the fastening holding only the rails raised as much, moved up as far on a pad as wide as it
|
||||
auto const &span { Model.spans[ under->part ] };
|
||||
auto const a { under->placed( span.x, under->scale ) };
|
||||
auto const b { under->placed( span.y, under->scale ) };
|
||||
pads.push_back( pad( *under, std::min( a, b ), std::max( a, b ), Model.bed, Model.heights[ under->part ].x + static_cast<float>( rail.rise ) ) );
|
||||
under->lift = static_cast<float>( rail.rise );
|
||||
lifted[ which ] = true;
|
||||
continue;
|
||||
}
|
||||
// the rail on a pad of its own on the fastening, as wide as its foot, short of the rails beside
|
||||
auto low { rail.foot };
|
||||
auto high { rail.foot };
|
||||
if( index > 0 ) {
|
||||
low = std::min( low, 0.5 * ( rail.at - Rails[ index - 1 ].at ) - fastening_gap );
|
||||
}
|
||||
if( index + 1 < Rails.size() ) {
|
||||
high = std::min( high, 0.5 * ( Rails[ index + 1 ].at - rail.at ) - fastening_gap );
|
||||
}
|
||||
if( low + high < pad_narrowest ) {
|
||||
continue;
|
||||
}
|
||||
fastening const at { padpart, Beam.from + ( Beam.to - Beam.from ) * ( rail.at / glm::length( plan( Beam.to - Beam.from ) ) ), axis };
|
||||
pads.push_back( pad( at, -low, high, Model.seat, Model.seat + static_cast<float>( rail.rise ) ) );
|
||||
}
|
||||
Fastenings.insert( Fastenings.end(), pads.begin(), pads.end() );
|
||||
}
|
||||
|
||||
std::vector<fastening_row> check_fastenings() {
|
||||
|
||||
std::vector<fastening_row> result;
|
||||
@@ -654,6 +731,9 @@ std::vector<fastening_row> check_fastenings() {
|
||||
row.bares.push_back( at );
|
||||
}
|
||||
for( auto const &fastening : fastenings ) {
|
||||
if( fastening.pad ) {
|
||||
continue;
|
||||
}
|
||||
++row.parts[ fastening.part ];
|
||||
auto const at { glm::dot( plan( fastening.point ) - start, axis ) };
|
||||
auto const turn { glm::dot( fastening.across, axis ) };
|
||||
@@ -763,6 +843,9 @@ std::vector<check_rail_gap> check_rail_seats() {
|
||||
auto const b { Fastening.placed( model->spans[ Fastening.part ].y, Fastening.scale ) };
|
||||
return along >= std::min( a, b ) && along <= std::max( a, b ); } ); };
|
||||
for( auto const &fastening : fastenings ) {
|
||||
if( fastening.pad ) {
|
||||
continue;
|
||||
}
|
||||
seats.push_back( plan( fastening.point ) + fastening.across * fastening.placed( 0.0, fastening.scale ) );
|
||||
if( fastening.part == part_check ) {
|
||||
seats.push_back( plan( fastening.point ) + fastening.across * fastening.placed( check_seats, fastening.scale ) );
|
||||
|
||||
@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "world/Knots.h"
|
||||
#include "world/TrackSleepers.h"
|
||||
|
||||
// the fastenings of the rails on the timbers: where a rail lies on a timber, the part of the model of the timbers which holds it
|
||||
@@ -32,6 +33,9 @@ struct fastening {
|
||||
float shift { 0.f }; // along its x, how far the pivot is moved
|
||||
bool both { false }; // the fastening of two rails close beside each other, neither with a check rail of its own seated
|
||||
bool whole { false }; // holding more rails than its seats, out to its ends: not narrowed
|
||||
float lift { 0.f }; // how far up it's moved, under a rail of the low section raised as a blade
|
||||
float height { 1.f }; // along its y, from the bottom of the part: a pad stretched to fill under a raised rail
|
||||
bool pad { false }; // under a raised rail or its fastening, not holding a rail itself
|
||||
// where an x of the part lands along its across, at the scale
|
||||
double placed( double const X, double const Scale ) const {
|
||||
return pivot + shift + Scale * ( X - pivot ); }
|
||||
@@ -60,6 +64,7 @@ private:
|
||||
TTrack *track { nullptr };
|
||||
int path { 0 };
|
||||
int side { 1 };
|
||||
knots::line rises; // of its foot, along the path, a wing rail of the low section raised as the blades
|
||||
std::vector<glm::dvec2> points;
|
||||
std::vector<double> heights;
|
||||
std::vector<glm::dvec2> inward; // unit vectors in plan from the rail toward the middle of its path
|
||||
@@ -79,6 +84,7 @@ private:
|
||||
role kind { role::plain };
|
||||
glm::dvec2 inward { 1.0, 0.0 };
|
||||
double foot { 0.0 };
|
||||
double rise { 0.0 };
|
||||
};
|
||||
|
||||
// the rails lying on the timber, in the order along it, one where several lie on one another, but the blades
|
||||
@@ -86,6 +92,9 @@ private:
|
||||
// the fastenings of rails close by fitted to the room between them: narrowed across, a plate cut short at the fastening of the
|
||||
// rail beside it or left out, the plates of two rails lying over each other made one
|
||||
static void fit( std::vector<fastening> &Fastenings, beam const &Beam, beam_model const &Model );
|
||||
// the fastenings under the raised rails: one holding only rails raised as much moved up as far on a pad, a rail raised
|
||||
// over a fastening with others on a pad of its own on it
|
||||
static void lift( std::vector<fastening> &Fastenings, std::vector<hit> const &Rails, beam const &Beam, beam_model const &Model );
|
||||
|
||||
std::vector<rail> m_rails;
|
||||
};
|
||||
|
||||
@@ -122,13 +122,16 @@ beam_model const *find_model( std::string const &Name, std::string const &Skinna
|
||||
continue;
|
||||
}
|
||||
glm::vec2 span { std::numeric_limits<float>::max(), std::numeric_limits<float>::lowest() };
|
||||
glm::vec2 heights { std::numeric_limits<float>::max(), std::numeric_limits<float>::lowest() };
|
||||
auto const timber { part < timber_parts };
|
||||
vertices_of( model.parts[ part ], [&]( glm::vec3 const &Position ) {
|
||||
span = { std::min( span.x, Position.x ), std::max( span.y, Position.x ) };
|
||||
heights = { std::min( heights.x, Position.y ), std::max( heights.y, Position.y ) };
|
||||
if( timber ) {
|
||||
top = std::max( top, Position.y );
|
||||
} } );
|
||||
model.spans[ part ] = span;
|
||||
model.heights[ part ] = heights;
|
||||
if( timber ) {
|
||||
model.span = { std::min( model.span.x, span.x ), std::max( model.span.y, span.y ) };
|
||||
}
|
||||
@@ -155,6 +158,7 @@ beam_model const *find_model( std::string const &Name, std::string const &Skinna
|
||||
}
|
||||
std::sort( model.bands.begin(), model.bands.end() );
|
||||
// the rails sit on the seat of the sleeper, below the fastenings sticking up over it, or on the plate of the fastening
|
||||
model.bed = top;
|
||||
model.seat = ( Seat >= 0.f ? Seat : top );
|
||||
if( Seat < 0.f && model.fastened() ) {
|
||||
model.seat = std::max( top, surface_at( model.parts[ part_plate ], 0.f, 0.f ).value_or( top ) );
|
||||
|
||||
@@ -73,6 +73,9 @@ double constexpr check_least { 0.8 };
|
||||
double constexpr chair_lead { 0.3 };
|
||||
// how far from the stock rail toward its blade the slide plate of a chair is measured
|
||||
double constexpr slide_probe { 0.12 };
|
||||
// a rail raised less than this goes without a pad under it, and a pad narrower than the second one is left out
|
||||
double constexpr pad_least { 0.002 };
|
||||
double constexpr pad_narrowest { 0.02 };
|
||||
// how far two fastenings on a timber may reach over one another before the check counts them
|
||||
double constexpr fastening_overlap { 0.01 };
|
||||
// how far from the camera the fastenings are drawn at most
|
||||
|
||||
@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "world/SleeperRules.h"
|
||||
#include "world/SleeperWorker.h"
|
||||
#include "world/Track.h"
|
||||
#include "world/TrackRails.h"
|
||||
#include "simulation/simulation.h"
|
||||
#include "scene/scene.h"
|
||||
#include "utilities/utilities.h"
|
||||
@@ -67,7 +68,21 @@ bool lays( TTrack const &Track ) {
|
||||
|
||||
double blade_rise( TTrack const &Track ) {
|
||||
|
||||
return ( Track.eType == tt_Switch && lays( Track ) ? timber_model( Track )->slide : 0.0 );
|
||||
return ( Track.eType == tt_Switch ? wing_rise( Track ) : 0.0 );
|
||||
}
|
||||
|
||||
double wing_rise( TTrack const &Track ) {
|
||||
|
||||
return ( lays( Track ) ? timber_model( Track )->slide : 0.0 );
|
||||
}
|
||||
|
||||
glm::dvec2 stock_stretch( TTrack const &Track, int const Path, int const Side ) {
|
||||
|
||||
if( Track.eType != tt_Switch || Track.SwitchExtension == nullptr || Side != ( Track.SwitchExtension->RightSwitch == ( Path == 1 ) ? 1 : -1 ) ) {
|
||||
return glm::dvec2 { -1.0 };
|
||||
}
|
||||
auto const &shape { Track.blade( 1 - Path ) };
|
||||
return { std::max( 0.0, ( shape.valid ? shape.tip : 0.0 ) - chair_lead ), track_rails::blade_length( Track, 1 - Path ) };
|
||||
}
|
||||
|
||||
std::vector<std::pair<double, double>> shared_zones( TTrack const &Track, int const Path ) {
|
||||
@@ -255,9 +270,9 @@ void lay( TTrack &Track ) {
|
||||
place[ 1 ] = glm::vec4 { glm::vec3 { y }, 0.f };
|
||||
place[ 2 ] = glm::vec4 { glm::vec3 { glm::cross( across, y ) }, 0.f };
|
||||
place[ 3 ] = glm::vec4 { glm::vec3 { fastening.point - Track.m_origin }, 1.f };
|
||||
auto const pivot { glm::vec3 { fastening.pivot, 0.f, 0.f } };
|
||||
auto const pivot { glm::vec3 { fastening.pivot, parts.heights[ fastening.part ].x, 0.f } };
|
||||
laid.instances[ fastening.part ].emplace_back(
|
||||
glm::translate( glm::scale( glm::translate( place, glm::vec3 { fastening.shift, -parts.seat, 0.f } + pivot ), glm::vec3 { fastening.scale, 1.f, 1.f } ), -pivot ) );
|
||||
glm::translate( glm::scale( glm::translate( place, glm::vec3 { fastening.shift, fastening.lift - parts.seat, 0.f } + pivot ), glm::vec3 { fastening.scale, fastening.height, 1.f } ), -pivot ) );
|
||||
}
|
||||
}
|
||||
runbeams.emplace_back( middle, half );
|
||||
|
||||
@@ -72,6 +72,8 @@ struct beam_model {
|
||||
glm::vec2 span { -1.3f, 1.3f }; // from and to along x, of the most detailed submodels of the whole model
|
||||
float seat { 0.f }; // the height in the model the feet of the rails go to
|
||||
float slide { 0.f }; // how far over the seat the blades of a switch slide, on the slide plates of the chairs; 0 without chairs
|
||||
float bed { 0.f }; // the height in the model of the top of the timber
|
||||
std::array<glm::vec2, part_count> heights {}; // from and to along y, of the parts
|
||||
std::vector<float> bands; // the squared distances the levels of detail of the model are seen from, the nearest first
|
||||
float length() const { return span.y - span.x; }
|
||||
// the model has the fastenings of the rails, put where the rails lie on its timbers
|
||||
@@ -123,6 +125,11 @@ bool lays( TTrack const &Track );
|
||||
// how far the feet of the blades of the switch ride over those of its other rails, on the slide plates of the chairs of its
|
||||
// timbers; 0 where it lays none with chairs
|
||||
double blade_rise( TTrack const &Track );
|
||||
// how far the feet of its wing rails of the low section of the blades are raised as the blades; 0 where it lays no timbers with chairs
|
||||
double wing_rise( TTrack const &Track );
|
||||
// the stretch along the path its rail of Side is the stock rail of the blade of the other path along, with the slide chairs from
|
||||
// a little before the tip of the blade to its heel; from past to where there's none
|
||||
glm::dvec2 stock_stretch( TTrack const &Track, int const Path, int const Side );
|
||||
// where along the path of the track its rails lie on timbers shared with other tracks: where another track runs so near that
|
||||
// the plain sleepers of the two would touch, of the lengths of the models they'd be made of. this goes by the shape of the
|
||||
// tracks alone, so it holds whether the beams are drawn or not. the stretches in the order along the path, none where there
|
||||
|
||||
Reference in New Issue
Block a user