/*************************************************************************** file : braking4.cpp created : September 2026 copyright : (C) 2026 by Bernhard Wymann email : berniw@bluewin.ch ***************************************************************************/ /* This program is free software; you can redistribute it and/or modify it * under the GNU General Public License, version 2 or (at your option) any * later version. Distributed WITHOUT ANY WARRANTY, including MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See . */ #include #include #include #include "braking4.h" static constexpr int NUMERICAL_INTERVALS = 8; double brakingDistance(double initialSpeed, double finalSpeed, double a0, double b, BrakingModel model, int intervals) { if (!std::isfinite(initialSpeed) || !std::isfinite(finalSpeed) || initialSpeed < 0.0 || finalSpeed < 0.0) { return std::numeric_limits::infinity(); } if (initialSpeed <= finalSpeed) { return 0.0; } const double initialSquared = initialSpeed * initialSpeed; const double finalSquared = finalSpeed * finalSpeed; const double difference = (initialSpeed - finalSpeed) * (initialSpeed + finalSpeed); if (model == BrakingModel::Basic) { b = 0.0; } if (a0 <= 0.0 || !std::isfinite(initialSquared) || !std::isfinite(a0) || !std::isfinite(b) || std::min(a0 + b * initialSquared, a0 + b * finalSquared) <= 0.0) { return std::numeric_limits::infinity(); } if (b == 0.0) { return difference / (2.0 * a0); } if (model == BrakingModel::AeroBound) { const double weakest = std::min(a0 + b * initialSquared, a0 + b * finalSquared); return difference / (2.0 * weakest); } if (model == BrakingModel::AeroNumerical) { const int count = std::max(1, intervals); const double step = difference / count; double distance = 0.0; for (int i = 0; i < count; ++i) { const double low = std::min(initialSquared, finalSquared + i * step); const double high = std::min(initialSquared, finalSquared + (i + 1) * step); const double weakest = std::min(a0 + b * low, a0 + b * high); distance += step / (2.0 * weakest); } return distance; } const double z = b * difference / (a0 + b * finalSquared); if (z <= -1.0) { return std::numeric_limits::infinity(); } if (std::fabs(z) < 1e-8) { return difference / (2.0 * (a0 + b * finalSquared)) * (1.0 - z / 2.0); } return std::log1p(z) / (2.0 * b); } double allowedApproachSpeed(double finalSpeed, double distance, double a0, double b, BrakingModel model, double speedCap) { const double target = std::max(0.0, std::min(finalSpeed, speedCap)); if (distance <= 0.0 || target >= speedCap) { return target; } if (model == BrakingModel::Basic) { return std::min(speedCap, std::sqrt(target * target + 2.0 * std::max(0.0, a0) * distance)); } double low = target; double high = speedCap; for (int i = 0; i < 24; ++i) { const double candidate = 0.5 * (low + high); if (brakingDistance(candidate, target, a0, b, model, NUMERICAL_INTERVALS) <= distance) { low = candidate; } else { high = candidate; } } return low; } double cornerSpeed(double radius, double grip, double mass, double downforce, double speedCap) { if (radius <= 0.0 || grip <= 0.0 || mass <= 0.0) { return 0.0; } const double denominator = 1.0 - grip * downforce * radius / mass; if (denominator <= 0.0) { return speedCap; } return std::min(speedCap, std::sqrt(grip * 9.81 * radius / denominator)); }