17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-18 19:39:20 +02:00

fix: automatic coupler crashes, horns, compressor start delay, radio and cab lever sounds

- automatic couplers don't catch above the safe collision speed (#86): with crash damage on they couple at a
  closing speed of 15 km/h at most, a faster hit locks the coupling until the vehicles part and the collision
  runs its course. On the way: CollisionVelocity() read a head-on 10 + 10 km/h as 14.1 km/h (quaternions turn
  by half the angle), it's now taken from the touching ends; CollisionDetect() took the other vehicle's speed
  the wrong way round for vehicles facing each other. Head-on hits now derail sooner, at the intended limit,
- a single horn lever can't sound both tones at once (eu07/maszyna#392),
- a skid ends once the vehicle stops on locked wheels (eu07/maszyna#479),
- electronic destination signs are blanked at the end of the timetable (eu07/maszyna#446),
- horns need the air or the voltage to sound (eu07/maszyna#290, #76): HornType=[Pneumatic]|Electric and
  Horn3Type in Cntrl.; a pneumatic horn needs 0.2 MPa in the main reservoir (or the main pipe without one),
  an electric one the low voltage; the lever stays where it was put,
- compressor start delay (#67): CompressorStartDelay [s] in Brake., counted from the compressor getting its
  power, after the engine starts say; none by default,
- the channel and volume buttons of a radio without power do nothing (eu07/maszyna#429); the power check of
  the radio is TMoverParameters::RadioPowered(),
- a lever moved smoothly sounds the positions it passes (#83).

Sonar findings in the functions changed: nesting, nested conditionals, commented-out code, std::format,
references to const. Unit tests: test::pair for two vehicles running into each other, test_couplers,
test_horn, test_wheelslip, test_compressor, test_radio, test_gauge_positions.
This commit is contained in:
jerrrrycho
2026-10-17 14:41:59 +02:00
parent c7f9796387
commit ec345f94cb
21 changed files with 1235 additions and 171 deletions

View File

@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "vehicle.h"
#include "vehicle/DynObj.h"
#include <fstream>
#include <stdexcept>
@@ -159,6 +160,18 @@ vehicle::vehicle(definition const &Definition, double Velocity, std::string cons
}
void vehicle::step(track const &Track, double Dt) {
compute_forces(Dt);
compute_movement(Track, Dt, TLocation{0.0, 0.0, 0.0});
}
void vehicle::compute_forces(double Dt) {
if (m_pipepressure >= 0.0) {
m_mover->Pipe->CreatePress(m_pipepressure);
}
m_mover->ComputeTotalForce(Dt);
}
double vehicle::compute_movement(track const &Track, double Dt, TLocation const &Location) {
TTrackShape shape;
shape.Len = 1000.0;
shape.dHtrack = Track.gradient;
@@ -167,13 +180,8 @@ void vehicle::step(track const &Track, double Dt) {
param.friction = Track.friction;
param.CategoryFlag = 1;
TTractionParam const traction;
TLocation const location{0.0, 0.0, 0.0};
TRotation const rotation{0.0, 0.0, 0.0};
if (m_pipepressure >= 0.0) {
m_mover->Pipe->CreatePress(m_pipepressure);
}
m_mover->ComputeTotalForce(Dt);
m_mover->ComputeMovement(Dt, Dt, shape, param, traction, location, rotation);
return m_mover->ComputeMovement(Dt, Dt, shape, param, traction, Location, rotation);
}
void vehicle::run(double Seconds, track const &Track, double Dt) {
@@ -184,4 +192,88 @@ void vehicle::run(double Seconds, track const &Track, double Dt) {
}
}
// the physics reaches the vehicle next to it through TDynamicObject::MoverParameters only (neighbour_data). the
// tests can't make a TDynamicObject, whose constructor and members come with the rest of the engine, so the
// neighbour is a zeroed block of its size with just that pointer set: enough for the physics, which reads nothing
// else of it, and never used as a whole object
static_assert(alignof(TDynamicObject) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__);
namespace {
std::unique_ptr<std::byte[]> make_standin(TMoverParameters &Mover) {
auto standin{std::make_unique<std::byte[]>(sizeof(TDynamicObject))}; // zeroed
reinterpret_cast<TDynamicObject *>(standin.get())->MoverParameters = &Mover; // NOSONAR see above
return standin;
}
TDynamicObject *as_neighbour(std::byte *Standin) {
return reinterpret_cast<TDynamicObject *>(Standin); // NOSONAR see above
}
} // namespace
pair::pair(vehicle &First, int FirstEnd, vehicle &Second, int SecondEnd, double Gap) {
auto const &first{First.mover()};
auto const &second{Second.mover()};
// the first vehicle in the middle, its FirstEnd towards the second one
m_vehicles[0] = {&First, FirstEnd, 0.0, FirstEnd == end::front ? 1.0 : -1.0, make_standin(First.mover())};
m_vehicles[1] = {&Second, SecondEnd, 0.5 * first.Dim.L + Gap + 0.5 * second.Dim.L, SecondEnd == end::front ? -1.0 : 1.0, make_standin(Second.mover())};
}
pair::~pair() {
for (auto const &placed : m_vehicles) {
// the vehicles outlive the pair, they mustn't point at its stand-ins
for (auto &neighbour : placed.owner->mover().Neighbours) {
neighbour = neighbour_data();
}
}
}
void pair::find_neighbours() {
// as TDynamicObject::update_neighbours()
for (auto const &placed : m_vehicles) {
placed.owner->mover().Loc = TLocation{placed.position, 0.0, 0.0};
}
for (int i = 0; i < 2; ++i) {
auto const &self{m_vehicles[i]};
auto const &other{m_vehicles[1 - i]};
auto &mover{self.owner->mover()};
auto const &othermover{other.owner->mover()};
auto &neighbour{mover.Neighbours[self.end]};
neighbour.vehicle = as_neighbour(other.standin.get());
neighbour.vehicle_end = other.end;
neighbour.distance = static_cast<float>(TMoverParameters::CouplerDist(&mover, &othermover) - mover.Couplers[self.end].adapter_length -
othermover.Couplers[other.end].adapter_length);
mover.Neighbours[1 - self.end] = neighbour_data();
}
}
void pair::step(track const &Track, double Dt) {
find_neighbours();
for (auto const &placed : m_vehicles) {
placed.owner->compute_forces(Dt);
}
for (auto &placed : m_vehicles) {
placed.position += placed.heading * placed.owner->compute_movement(Track, Dt, TLocation{placed.position, 0.0, 0.0});
}
}
void pair::run(double Seconds, track const &Track, double Dt) {
// whole steps, as in vehicle::run()
auto const steps{std::lround(Seconds / Dt)};
for (long i = 0; i < steps; ++i) {
step(Track, Dt);
}
}
double pair::gap() const {
auto const &first{m_vehicles[0].owner->mover()};
auto const &second{m_vehicles[1].owner->mover()};
return std::abs(m_vehicles[1].position - m_vehicles[0].position) - 0.5 * (first.Dim.L + second.Dim.L);
}
int pair::coupling() const {
return m_vehicles[0].owner->mover().Couplers[m_vehicles[0].end].CouplingFlag;
}
} // namespace test