mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-01 23:59:12 +01:00
feat(sleepers): the timbers of a switch get the fastenings of the rails from the submodels plate, chair and check of their model: a plate under each rail where it lies on a timber, slide chairs under the stock rails along the blades, a fastening of both where a check rail or another rail of the frog lies close beside, the legs of the nose in one plate where they're joined; the rails sit on the plate, the blades ride on the slide plates of the chairs as high as the model has them, their webs shortened; the fastenings drawn within 120 m; selftest fastenings
This commit is contained in:
@@ -25,6 +25,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
|
||||
namespace track_sleepers {
|
||||
|
||||
@@ -50,6 +51,40 @@ void vertices_of( TSubModel *Submodel, Visit Visitor ) {
|
||||
}
|
||||
}
|
||||
|
||||
// the highest the faces of the submodel reach over the point of the plan of the model, in the space of the model; none where
|
||||
// no face lies over it
|
||||
std::optional<float> surface_at( TSubModel *Submodel, float const X, float const Z ) {
|
||||
|
||||
glm::mat4 transform { 1.f };
|
||||
if( ( Submodel->iFlags & 0xC000 ) && ( Submodel->GetMatrix() != nullptr ) ) {
|
||||
transform = glm::make_mat4( Submodel->GetMatrix()->readArray() );
|
||||
}
|
||||
auto const indexed { Submodel->m_geometry.handle != null_handle };
|
||||
auto const &vertices { indexed ? GfxRenderer->Vertices( Submodel->m_geometry.handle ) : Submodel->Vertices };
|
||||
auto const &indices { indexed ? GfxRenderer->Indices( Submodel->m_geometry.handle ) : Submodel->Indices };
|
||||
auto const count { indices.empty() ? vertices.size() : indices.size() };
|
||||
auto const corner = [&]( std::size_t const Index ) {
|
||||
return glm::vec3 { transform * glm::vec4 { vertices[ indices.empty() ? Index : indices[ Index ] ].position, 1.f } }; };
|
||||
std::optional<float> result;
|
||||
for( std::size_t index = 0; index + 2 < count; index += 3 ) {
|
||||
auto const a { corner( index ) };
|
||||
auto const b { corner( index + 1 ) };
|
||||
auto const c { corner( index + 2 ) };
|
||||
auto const area { ( b.x - a.x ) * ( c.z - a.z ) - ( c.x - a.x ) * ( b.z - a.z ) };
|
||||
if( std::abs( area ) < 1e-9f ) {
|
||||
continue;
|
||||
}
|
||||
auto const u { ( ( X - a.x ) * ( c.z - a.z ) - ( c.x - a.x ) * ( Z - a.z ) ) / area };
|
||||
auto const v { ( ( b.x - a.x ) * ( Z - a.z ) - ( X - a.x ) * ( b.z - a.z ) ) / area };
|
||||
if( u < -1e-5f || v < -1e-5f || u + v > 1.f + 1e-5f ) {
|
||||
continue;
|
||||
}
|
||||
auto const height { a.y + u * ( b.y - a.y ) + v * ( c.y - a.y ) };
|
||||
result = ( result ? std::max( *result, height ) : height );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// the model of the beams of the name and skin, loaded and measured on the first use; null when it can't be loaded. the feet of
|
||||
// the rails go to the given seat in it, or to its top where the seat is below zero
|
||||
beam_model const *find_model( std::string const &Name, std::string const &Skinname, float const Seat ) {
|
||||
@@ -74,16 +109,16 @@ beam_model const *find_model( std::string const &Name, std::string const &Skinna
|
||||
model.skin = GfxRenderer->Fetch_Material( Skin );
|
||||
}
|
||||
// a timber put together from its parts, with a part between the ends stretched and repeated to the length
|
||||
std::array<char const *, part_count> const names { "begin", "main", "end" };
|
||||
std::array<char const *, part_count> const names { "begin", "main", "end", "plate", "chair", "check" };
|
||||
model.stretchable = true;
|
||||
for( int part = 0; part < part_count; ++part ) {
|
||||
model.parts[ part ] = model.model->GetFromName( names[ part ] );
|
||||
model.stretchable = model.stretchable && model.parts[ part ] != nullptr;
|
||||
model.stretchable = model.stretchable && ( part >= timber_parts || model.parts[ part ] != nullptr );
|
||||
}
|
||||
auto top { std::numeric_limits<float>::lowest() };
|
||||
model.span = { std::numeric_limits<float>::max(), std::numeric_limits<float>::lowest() };
|
||||
if( model.stretchable ) {
|
||||
for( int part = 0; part < part_count; ++part ) {
|
||||
for( int part = 0; part < timber_parts; ++part ) {
|
||||
glm::vec2 span { std::numeric_limits<float>::max(), std::numeric_limits<float>::lowest() };
|
||||
vertices_of( model.parts[ part ], [&]( glm::vec3 const &Position ) {
|
||||
span = { std::min( span.x, Position.x ), std::max( span.y, Position.x ) };
|
||||
@@ -112,8 +147,14 @@ 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
|
||||
// the rails sit on the seat of the sleeper, below the fastenings sticking up over it, or on the plate of the fastening
|
||||
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 ) );
|
||||
}
|
||||
if( model.fastened() && model.parts[ part_chair ] != nullptr ) {
|
||||
model.slide = std::max( 0.f, surface_at( model.parts[ part_chair ], static_cast<float>( -slide_probe ), 0.f ).value_or( model.seat ) - model.seat );
|
||||
}
|
||||
if( model.length() < 0.5f ) {
|
||||
ErrorLog( "Bad sleepers3d: model \"" + Name + "\" has no beam along x" );
|
||||
model.model = nullptr;
|
||||
@@ -125,7 +166,11 @@ beam_model const *find_model( std::string const &Name, std::string const &Skinna
|
||||
+ ( model.stretchable ?
|
||||
", main " + to_string( model.spans[ part_main ].x, 3 ) + ".." + to_string( model.spans[ part_main ].y, 3 ) :
|
||||
std::string {} )
|
||||
+ ", seat " + to_string( model.seat, 3 ) );
|
||||
+ ( model.fastened() ?
|
||||
std::string { ", fastenings plate" } + ( model.parts[ part_chair ] != nullptr ? " chair" : "" ) + ( model.parts[ part_check ] != nullptr ? " check" : "" ) :
|
||||
std::string {} )
|
||||
+ ", seat " + to_string( model.seat, 3 )
|
||||
+ ( model.slide > 0.f ? ", slide " + to_string( model.slide, 3 ) : std::string {} ) );
|
||||
return &model;
|
||||
}
|
||||
return ( found->second.model != nullptr ? &found->second : nullptr );
|
||||
|
||||
Reference in New Issue
Block a user