17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-31 04:12:20 +01:00

fix(physics): automatic couplers don't catch above the safe collision speed (#86)

This commit is contained in:
jerrrrycho
2026-10-15 21:20:35 +02:00
parent b400255dae
commit 71be884ed9
11 changed files with 192 additions and 20 deletions

39
tests/unit/test_horn.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include "stdafx.h"
#include "doctest.h"
#include "vehicle/horn.h"
// the horn keys of the cab: low tone (A) and high tone (shift+A), held to sound
TEST_CASE("horn: a single lever for both tones sounds one tone at a time (eu07/maszyna#392)") {
auto signal{0};
signal = horn::pressed(signal, horn::low, true);
REQUIRE(signal == horn::low);
// the lever moved over to the high tone while the low tone key is still held
signal = horn::pressed(signal, horn::high, true);
CHECK(signal == horn::high);
// letting go of the low tone key leaves the high tone sounding
signal = horn::released(signal, horn::low);
CHECK(signal == horn::high);
signal = horn::released(signal, horn::high);
CHECK(signal == 0);
}
TEST_CASE("horn: separate buttons for the tones can sound both at once") {
auto signal{0};
signal = horn::pressed(signal, horn::low, false);
signal = horn::pressed(signal, horn::high, false);
CHECK(signal == (horn::low | horn::high));
signal = horn::released(signal, horn::low);
CHECK(signal == horn::high);
}
TEST_CASE("horn: releasing a tone leaves the other bits of the signal alone") {
auto const third{4}; // the third horn, operated separately
CHECK(horn::released(horn::low | third, horn::low) == third);
CHECK(horn::pressed(third, horn::high, true) == (horn::high | third));
}

View File

@@ -0,0 +1,63 @@
#include "stdafx.h"
#include "doctest.h"
#include "vehicle.h"
using test::definition;
using test::track;
using test::vehicle;
namespace {
struct braking_result {
bool skidded{false}; // the wheels locked while braking
bool stopped{false}; // came (almost) to a stop on the braking rail
};
// brakes the wagon from 40 km/h on the Braking rail until it's (nearly) stopped, then has it stand on the
// Standing one for 30 seconds
braking_result brake_to_stop_then_stand(vehicle &Coach, track const &Braking, track const &Standing) {
braking_result result;
Coach.hold_brake_pipe(5.0);
Coach.run(5.0, Braking);
Coach.hold_brake_pipe(3.5); // service braking
// a skidding wagon brakes on the sliding adhesion only, give it time
for (double t = 0.0; t < 600.0; t += 0.01) {
result.skidded |= Coach->SlippingWheels;
auto const speed{std::abs(Coach.speed())};
if (speed > 0.0 && speed < 0.1) {
// almost stopped; a skidding wagon is still skidding at this point
result.stopped = true;
break;
}
Coach.step(Braking);
}
Coach.run(30.0, Standing);
return result;
}
} // namespace
// the engine doesn't let a stopped, braked vehicle slip (the Vel > 0.1 trap in TMoverParameters::ComputeTotalForce),
// so a wagon which stopped in a skid should be no different from one which stopped without it. it used to stay
// skidding instead, with its brakes capped by the sliding adhesion, and slid or crept away (eu07/maszyna#479)
TEST_CASE("wheelslip: a wagon which stopped in a skid holds like one which stopped without it") {
track const dry{0.15, 0.0};
track const slippery{0.02, 0.0};
// held only by the brakes: the sliding adhesion on this rail is too low for the slope
track const slipperyslope{0.02, 0.08};
vehicle normal{definition::load("wagon"), 40.0};
auto const normalbraking{brake_to_stop_then_stand(normal, dry, slipperyslope)};
vehicle skidding{definition::load("wagon"), 40.0};
auto const skiddingbraking{brake_to_stop_then_stand(skidding, slippery, slipperyslope)};
// the test means something only when the braking went as planned
REQUIRE(normalbraking.stopped);
REQUIRE_FALSE(normalbraking.skidded);
REQUIRE(skiddingbraking.stopped);
REQUIRE(skiddingbraking.skidded);
CHECK(std::abs(normal.speed()) < 0.1);
CHECK(std::abs(skidding.speed()) < 0.1);
CHECK_FALSE(skidding->SlippingWheels);
}