From 9bd79d03d112a0602eecf633607843f735eb425e Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Mon, 21 Jun 2021 00:17:41 +0200 Subject: [PATCH] Fix speed calculation --- src/train_gui.cpp | 70 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/src/train_gui.cpp b/src/train_gui.cpp index 087abfb9e4..5fff01d417 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -405,6 +405,65 @@ int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab) return num; } +int GetAcceleration(const Train *train, const int speed, const int mass) +{ + const int64 power = train->gcache.cached_power * 746ll; + int64 resistance = 0; + + const bool maglev = (GetRailTypeInfo(train->railtype)->acceleration_type == 2); + + if (!maglev) { + /* Static resistance plus rolling friction. */ + resistance = 10 * mass; + resistance += mass * (15 * (512 + speed) / 512); + } + + const int area = 14; + + resistance += (area * train->gcache.cached_air_drag * speed * speed) / 1000; + + uint32 max_te = train->gcache.cached_max_te; // [N] + int64 force; + + if (speed > 0) { + if (!maglev) { + /* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */ + force = power * 18 / (speed * 5); + + if (force > static_cast(max_te)) { + force = max_te; + } + } else { + force = power / 25; + } + } else { + force = (!maglev) ? std::min(max_te, power) : power; + force = std::max(force, (mass * 8) + resistance); + } + + /* Easy way out when there is no acceleration. */ + if (force == resistance) return 0; + + int acceleration = ClampToI32((force - resistance) / (mass * 4)); + acceleration = force < resistance ? std::min(-1, acceleration) : std::max(1, acceleration); + + return acceleration; +} + +int GetMaxSpeed(const Train *train, const int mass, const int speed_cap) +{ + int max_speed = 0; + int acceleration; + + do + { + max_speed++; + acceleration = GetAcceleration(train, max_speed, mass); + } while (acceleration > 0 && max_speed < speed_cap); + + return max_speed; +} + /** * Draw the details for the given vehicle at the given position * @@ -514,8 +573,6 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po Money feeder_share = 0; int empty_weight = 0; int loaded_weight = 0; - int empty_max_speed = 0; - int loaded_max_speed = 0; for (const Vehicle *u = v; u != nullptr; u = u->Next()) { const Train *train = Train::From(u); @@ -527,13 +584,8 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po loaded_weight += weight_without_cargo + train->GetCargoWeight(train->cargo_cap); } - const auto rolling_friction = 15 * (512 + v->GetDisplayMaxSpeed()) / 512; - const auto tractive_effort_empty = empty_weight * rolling_friction; - const auto tractive_effort_loaded = loaded_weight * rolling_friction; - const int power = static_cast(v->gcache.cached_power * 746); - const int max_te = static_cast(v->gcache.cached_max_te); - empty_max_speed = std::min(v->GetDisplayMaxSpeed(), (tractive_effort_empty == 0 || tractive_effort_empty > max_te) ? 0 : static_cast((3.6 * power) / tractive_effort_empty)); - loaded_max_speed = std::min(v->GetDisplayMaxSpeed(), (tractive_effort_loaded == 0 || tractive_effort_loaded > max_te) ? 0 : static_cast((3.6 * power) / tractive_effort_loaded)); + const int empty_max_speed = GetMaxSpeed(v, empty_weight, v->GetDisplayMaxSpeed()); + const int loaded_max_speed = GetMaxSpeed(v, loaded_weight, v->GetDisplayMaxSpeed()); if (--vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) { SetDParam(0, empty_weight);