public static Lut LoadCarTorque(IDataWrapper data, bool considerLimiter = true, int detalization = 100) {
/* read torque curve and engine params */
var torqueFile = data.GetLutFile("power.lut");
if (torqueFile.IsEmptyOrDamaged()) throw new FileNotFoundException("Cannot load power.lut", "data/power.lut");
var engine = data.GetIniFile("engine.ini");
if (engine.IsEmptyOrDamaged()) throw new FileNotFoundException("Cannot load engine.ini", "data/engine.ini");
/* prepare turbos and read controllers */
var turbos = ReadTurbos(engine);
for (var i = 0; i < turbos.Count; i++) {
turbos[i].Controllers = ReadControllers(data.GetIniFile($"ctrl_turbo{i}.ini"));
}
/* prepare torque curve and limits */
var torque = torqueFile.Values;
torque.UpdateBoundingBox();
var limit = considerLimiter && engine.ContainsKey("ENGINE_DATA") ? engine["ENGINE_DATA"].GetDouble("LIMITER", torque.MaxX) : torque.MaxX;
var startFrom = considerLimiter ? 0d : torque.MinX;
/* build smoothed line */
var result = new Lut();
var previousTorquePoint = 0;
var previousRpm = 0d;
for (var i = 0; i <= detalization; i++) {
var rpm = detalization == 0 ? limit : (limit - startFrom) * i / detalization + startFrom;
for (var j = previousTorquePoint; j < torque.Count; j++) {
var p = torque[j];
if (p.X > rpm) {
previousTorquePoint = j > 0 ? j - 1 : 0;
break;
}
if ((i == 0 || p.X > previousRpm) && p.X < rpm && p.X >= 0) {
result.Add(new LutPoint(p.X, ConsiderTurbo(turbos, p.X, p.Y)));
}
}
var baseTorque = torque.InterpolateLinear(rpm);
result.Add(new LutPoint(rpm, ConsiderTurbo(turbos, rpm, baseTorque)));
previousRpm = rpm;
}
return result.Optimize();
}