diff --git a/Assets/frictions/default.tire b/Assets/frictions/default.tire index e2532c9..728b15d 100644 --- a/Assets/frictions/default.tire +++ b/Assets/frictions/default.tire @@ -1,5 +1,56 @@ { - "Pacejka": {}, + "Pacejka": { + "Lateral": { + "a0": 1.4, + "a1": -0, + "a2": 1688, + "a3": 2400, + "a4": 6.026, + "a5": 0, + "a6": -0.359, + "a7": 1, + "a8": 0, + "a9": 0, + "a10": 0, + "a111": 0, + "a112": 0, + "a12": 0, + "a13": 0 + }, + "Longitudinal": { + "b0": 1.65, + "b1": 0, + "b2": 1690, + "b3": 0, + "b4": 229, + "b5": 0, + "b6": 0, + "b7": 0, + "b8": -10, + "b9": 0, + "b10": 0 + }, + "Aligning": { + "c0": 2, + "c1": -3.8, + "c2": -3.14, + "c3": -1.16, + "c4": -7.2, + "c5": 0, + "c6": 0, + "c7": 0.044, + "c8": -0.58, + "c9": 0.18, + "c10": 0, + "c11": 0, + "c12": 0, + "c13": 0, + "c14": 0.14, + "c15": -1.029, + "c16": 0, + "c17": 0 + } + }, "RollResistanceLin": 0.001, "RollResistanceQuad": 1E-06, "__references": [], diff --git a/Code/Base/Powertrain/Engine.cs b/Code/Base/Powertrain/Engine.cs index 54756a4..400f67e 100644 --- a/Code/Base/Powertrain/Engine.cs +++ b/Code/Base/Powertrain/Engine.cs @@ -87,7 +87,7 @@ public class Engine : PowertrainComponent angularVelocity += finalTorque / inertiaSum * Time.Delta; angularVelocity = Math.Max( angularVelocity, 0 ); - //UpdateStream(); + UpdateStream(); return finalTorque; } diff --git a/Code/Base/Powertrain/PowerWheel.cs b/Code/Base/Powertrain/PowerWheel.cs index fa9d1e2..437cf08 100644 --- a/Code/Base/Powertrain/PowerWheel.cs +++ b/Code/Base/Powertrain/PowerWheel.cs @@ -7,7 +7,11 @@ public class PowerWheel : PowertrainComponent { [Property] public VeloXWheel Wheel { get; set; } - public override float QueryInertia() => Wheel.Inertia; + public override float QueryInertia() + { + float dtScale = Math.Clamp( Time.Delta, 0.01f, 0.05f ) / 0.005f; + return Wheel.BaseInertia * dtScale; + } public override float QueryAngularVelocity( float angularVelocity ) { @@ -19,7 +23,8 @@ public class PowerWheel : PowertrainComponent Wheel.AutoPhysics = false; Wheel.Torque = torque; Wheel.Brake = Vehicle.Brake; - + Inertia = Wheel.BaseInertia + inertia; + Wheel.Inertia = inertia; Wheel.DoPhysics( Vehicle ); angularVelocity = Wheel.AngularVelocity; diff --git a/Code/Base/Wheel/Pacejka.cs b/Code/Base/Wheel/Pacejka.cs index a43ec92..ac3dde6 100644 --- a/Code/Base/Wheel/Pacejka.cs +++ b/Code/Base/Wheel/Pacejka.cs @@ -167,7 +167,7 @@ public class Pacejka /// pacejka magic formula for longitudinal force - public float PacejkaFx( float sigma, float Fz, float friction_coeff ) + public float PacejkaFx( float sigma, float Fz, float friction_coeff, out float maxforce_output ) { var b = Longitudinal; @@ -198,6 +198,7 @@ public class Pacejka // scale by surface friction Fx *= friction_coeff; + maxforce_output = D; return Fx; } diff --git a/Code/Base/Wheel/TirePreset.cs b/Code/Base/Wheel/TirePreset.cs index eee29ad..03b9328 100644 --- a/Code/Base/Wheel/TirePreset.cs +++ b/Code/Base/Wheel/TirePreset.cs @@ -24,12 +24,24 @@ public class TirePreset : GameResource return resistance; } - public void ComputeSlip( float vlon, float vlat, float vrot, out float slip_ratio, out float slip_angle ) + public static void ComputeSlip( float lon_velocity, float lat_velocity, float rot_velocity, float wheel_radius, out float slip_ratio, out float slip_angle ) { - float rvlon = 1 / MathF.Max( MathF.Abs( vlon ), 1E-3f ); - float vslip = vrot - vlon; - slip_ratio = vslip * rvlon; - slip_angle = -MathF.Atan( vlat * rvlon ); + var abs_lon = Math.Max( MathF.Abs( lon_velocity ), 1e-3f ); + + slip_ratio = lon_velocity - rot_velocity * wheel_radius; + + if ( abs_lon >= 0.005f ) + slip_ratio /= abs_lon; + else + slip_ratio *= abs_lon; + + if ( abs_lon >= 0.5f ) + slip_angle = MathF.Atan2( -lat_velocity, abs_lon ).RadianToDegree() / 50f; + else + slip_angle = -lat_velocity * (0.01f / Time.Delta); + + slip_ratio = Math.Clamp( slip_ratio, -1, 1 ); + slip_angle = Math.Clamp( slip_angle, -1, 1 ); } @@ -40,104 +52,6 @@ public class TirePreset : GameResource return ((1 / 6.0f) * (sc * sc) + 1) * sc; } - public struct TireState() - { - /// - /// surface friction coefficient - /// - public float friction = 0; - - /// - /// tire camber angle relative to track surface - /// - public float camber = 0; - - /// - /// camber thrust induced lateral slip velocity - /// - public float vcam = 0; - - /// - /// ratio of tire contact patch speed to road speed - /// - public float slip = 0; - - /// - /// the angle between the wheel heading and the wheel velocity - /// - public float slip_angle = 0; - - /// - /// peak force slip ratio - /// - public float ideal_slip = 0; - - /// - /// peak force slip angle - /// - public float ideal_slip_angle = 0; - - /// - /// positive during traction - /// - public float fx = 0; - - /// - /// positive during traction in a right turn - /// - public float fy = 0; - - /// - /// positive during traction in a left turn - /// - public float mz = 0; - }; - - public void ComputeState( - float normal_force, - float rot_velocity, - float lon_velocity, - float lat_velocity, - float camber_angle, - out TireState s - ) - { - s = new TireState - { - camber = camber_angle, - friction = 1.0f - }; - - if ( normal_force * s.friction < 1E-6f ) - { - s.slip = s.slip_angle = 0; - s.fx = s.fy = s.mz = 0; - return; - } - - float Fz = MathF.Min( normal_force * 0.001f, 30f ); - - ComputeSlip( lon_velocity, lat_velocity, rot_velocity, out float slip, out float slip_angle ); - float sigma = slip; - float alpha = slip_angle.RadianToDegree(); - float gamma = s.camber.RadianToDegree(); - - float Fx0 = Pacejka.PacejkaFx( sigma, Fz, s.friction ); - float Fy0 = Pacejka.PacejkaFy( alpha, Fz, gamma, s.friction, out float camber_alpha ); - - // combined slip - float Gx = Pacejka.PacejkaGx( slip, slip_angle ); - float Gy = Pacejka.PacejkaGy( slip, slip_angle ); - float Fx = Gx * Fx0; - float Fy = Gy * Fy0; - - s.vcam = ComputeCamberVelocity( camber_alpha.DegreeToRadian(), lon_velocity ); - s.slip = slip; - s.slip_angle = slip_angle; - s.fx = Fx; - s.fy = Fy; - } - public static float ComputeCamberVelocity( float sa, float vx ) { float tansa = (1 / 3.0f * (sa * sa) + 1) * sa; diff --git a/Code/Base/Wheel/VeloXWheel.cs b/Code/Base/Wheel/VeloXWheel.cs index 9651ede..6e84067 100644 --- a/Code/Base/Wheel/VeloXWheel.cs +++ b/Code/Base/Wheel/VeloXWheel.cs @@ -1,10 +1,14 @@ using Sandbox; +using Sandbox.Rendering; using Sandbox.Services; using System; using System.Collections.Specialized; using System.Numerics; using System.Text.RegularExpressions; +using System.Threading; using static Sandbox.CameraComponent; +using static Sandbox.Package; +using static Sandbox.SkinnedModelRenderer; namespace VeloX; @@ -40,7 +44,7 @@ public partial class VeloXWheel : Component public float Spin { get; private set; } public float RPM { get => angularVelocity * 30f / MathF.PI; set => angularVelocity = value / (30f / MathF.PI); } - public float AngularVelocity => angularVelocity; + public float AngularVelocity { get => angularVelocity; set => angularVelocity = value; } internal float DistributionFactor { get; set; } @@ -65,8 +69,12 @@ public partial class VeloXWheel : Component private Vector3 force; public float CounterTorque { get; private set; } - private float BaseInertia => Mass * MathF.Pow( Radius.InchToMeter(), 2 ); - public float Inertia => BaseInertia; + internal float BaseInertia => 0.5f * Mass * MathF.Pow( Radius.InchToMeter(), 2 ); + public float Inertia + { + get => BaseInertia + inertia; + set => inertia = value; + } protected override void OnAwake() @@ -83,12 +91,8 @@ public partial class VeloXWheel : Component private void UpdateVisuals( VeloXBase vehicle, in float dt ) { - var entityAngles = vehicle.WorldRotation; - - Spin -= angularVelocity.MeterToInch() * dt; - + Spin -= angularVelocity.RadianToDegree() * dt; WorldRotation = vehicle.WorldTransform.RotationToWorld( GetSteer( vehicle.SteerAngle.yaw ) ) * Rotation.FromAxis( Vector3.Right, Spin ); - } private Rotation GetSteer( float steer ) @@ -108,16 +112,14 @@ public partial class VeloXWheel : Component private static float GetLongitudinalLoadCoefficient( float load ) => 11000 * (1 - MathF.Exp( -0.00014f * load )); private static float GetLateralLoadCoefficient( float load ) => 18000 * (1 - MathF.Exp( -0.0001f * load )); float lastload; + private float inertia; + public void DoPhysics( VeloXBase vehicle ) { var pos = vehicle.WorldTransform.PointToWorld( StartPos ); var ang = vehicle.WorldTransform.RotationToWorld( GetSteer( vehicle.SteerAngle.yaw ) ); - forward = ang.Forward; - right = ang.Right; - up = ang.Up; - var maxLen = SuspensionLength; var endPos = pos + ang.Down * maxLen; @@ -129,6 +131,12 @@ public partial class VeloXWheel : Component .UseHitPosition( false ) .WithoutTags( vehicle.WheelIgnoredTags ) .Run(); + //forward = ang.Forward; + //right = ang.Right; + up = ang.Up; + + forward = Vector3.VectorPlaneProject( ang.Forward, Trace.Normal ).Normal; + right = Vector3.VectorPlaneProject( ang.Right, Trace.Normal ).Normal; var fraction = Trace.Fraction; @@ -141,7 +149,9 @@ public partial class VeloXWheel : Component var normal = Trace.Normal; - var vel = vehicle.Body.GetVelocityAtPoint( pos ); + var vel = vehicle.Body.GetVelocityAtPoint( contactPos ); + + //var vel = vehicle.Body.GetVelocityAtPoint( pos ); if ( !IsOnGround ) { @@ -191,76 +201,105 @@ public partial class VeloXWheel : Component float camber_rad = CamberAngle.DegreeToRadian(); float R = Radius.InchToMeter(); - TirePreset.ComputeState( - 2500, - angularVelocity * R, - forwardSpeed, - sideSpeed, - camber_rad, - out var tireState - ); + + //TirePreset.ComputeState( + // load, + // angularVelocity, + // forwardSpeed, + // sideSpeed, + // camber_rad, + // R, + // Inertia, + // out var tireState + //); float linearSpeed = angularVelocity * Radius.InchToMeter(); float F_roll = TirePreset.GetRollingResistance( linearSpeed, 1.0f ); - F_roll = -MathF.Sign( forwardSpeed ) * F_roll; + F_roll *= -Math.Clamp( linearSpeed * 0.25f, -1, 1 ); - float Fx_total = tireState.fx + F_roll; + //float Fx_total = tireState.fx + F_roll; float T_brake = Brake * BrakePowerMax; if ( angularVelocity > 0 ) T_brake = -T_brake; else T_brake = angularVelocity < 0 ? T_brake : -MathF.Sign( Torque ) * T_brake; - float totalTorque = Torque + T_brake - Fx_total * R; + //float totalTorque = Torque + tireState.fx; - // not work - Vector3 c = pos.Cross( forward ); - Vector3 v = (c * vehicle.Body.PhysicsBody.Inertia).Cross( pos ); - var m = 1 / (1 / vehicle.Body.Mass + forward.Dot( v )); - m *= Inertia / (m * R * R + Inertia); - float ve = forward.Dot( vel ).InchToMeter() - angularVelocity; + angularVelocity += Torque / Inertia * Time.Delta; + angularVelocity += T_brake / Inertia * Time.Delta; + angularVelocity += F_roll * 9.80665f / Inertia * Time.Delta; + TirePreset.ComputeSlip( forwardSpeed, sideSpeed, angularVelocity, R, out var slip, out var slip_ang ); + var fx = TirePreset.Pacejka.PacejkaFx( slip, load, 1, out var maxTorque ); + var fy = TirePreset.Pacejka.PacejkaFy( slip_ang * load, load, camber_rad, 1, out var _ ); - angularVelocity += ve * m * Radius * (1 / Inertia);// totalTorque * (1 / Inertia) * Time.Delta; + maxTorque *= R; + var errorTorque = (angularVelocity - forwardSpeed / R) * Inertia / Time.Delta; + + var surfaceTorque = Math.Clamp( errorTorque, -maxTorque, maxTorque ); + + angularVelocity -= surfaceTorque / Inertia * Time.Delta; forwardFriction = new Friction() { - Slip = tireState.slip, - Force = Fx_total, + Slip = slip, + Force = -fx, Speed = forwardSpeed }; sideFriction = new Friction() { - Slip = tireState.slip_angle, - Force = tireState.fy, + Slip = slip_ang, + Force = fy, Speed = sideSpeed }; + Vector3 frictionForce = forward * forwardFriction.Force + right * sideFriction.Force; - vehicle.Body.ApplyForceAt( contactPos, (force + frictionForce) / Time.Delta ); - } - else - { - // Колесо в воздухе: сбрасываем силы - forwardFriction = new Friction(); - sideFriction = new Friction(); + vehicle.Body.ApplyForceAt( pos, force / Time.Delta * ProjectSettings.Physics.SubSteps ); + vehicle.Body.ApplyForceAt( pos, frictionForce * ProjectSettings.Physics.SubSteps ); - // Обновление угловой скорости только от мотора/тормозов - float T_brake = Brake * BrakePowerMax; - - if ( angularVelocity > 0 ) T_brake = -T_brake; - else T_brake = angularVelocity < 0 ? T_brake : -MathF.Sign( Torque ) * T_brake; - angularVelocity += (Torque + T_brake) / Inertia * Time.Delta; } } + //todo + protected (float Mass, float Inertia) CalcMassAndInertia() + { + // section width in millimeters, measured from sidewall to sidewall + // ratio of sidewall height to section width in percent + // diameter of the wheel in inches + var tire_size = new Vector3( 215, 45, 17 ); + + float tire_width = tire_size[0] * 0.001f; + float tire_aspect_ratio = tire_size[1] * 0.01f; + float tire_radius = tire_size[2] * 0.5f * 0.0254f + tire_width * tire_aspect_ratio; + float tire_thickness = 0.02f; + float tire_density = 1000; // rubber + + float rim_radius = tire_radius - tire_width * tire_aspect_ratio; + float rim_width = tire_width; + float rim_thickness = 0.01f; + float rim_density = 2700; // aluminium + + float tire_volume = float.Pi * tire_width * tire_thickness * (2 * tire_radius - tire_thickness); + float rim_volume = float.Pi * rim_width * rim_thickness * (2 * rim_radius - rim_thickness); + float tire_mass = tire_density * tire_volume; + float rim_mass = rim_density * rim_volume; + float tire_inertia = tire_mass * tire_radius * tire_radius; + float rim_inertia = rim_mass * rim_radius * rim_radius; + + float mass = tire_mass + rim_mass; + float inertia = tire_inertia + rim_inertia; + + return (mass, inertia); + } // debug protected override void OnUpdate() { - DebugOverlay.Normal( contactPos, forward * forwardFriction.Force / 100f, Color.Red, overlay: true ); - DebugOverlay.Normal( contactPos, right * sideFriction.Force / 100f, Color.Green, overlay: true ); + DebugOverlay.Normal( contactPos, forward * forwardFriction.Force / 1000f, Color.Red, overlay: true ); + DebugOverlay.Normal( contactPos, right * sideFriction.Force / 1000f, Color.Green, overlay: true ); DebugOverlay.Normal( contactPos, up * force / 1000f, Color.Blue, overlay: true ); } } diff --git a/Code/Car/VeloXCar.Steering.cs b/Code/Car/VeloXCar.Steering.cs index 52c2dbd..b110430 100644 --- a/Code/Car/VeloXCar.Steering.cs +++ b/Code/Car/VeloXCar.Steering.cs @@ -14,33 +14,40 @@ public partial class VeloXCar [Property, Feature( "Steer" )] public float MaxSteerAngle { get; set; } = 35f; [Sync] public float Steering { get; private set; } - private float jTurnMultiplier; private float inputSteer; + + public static float SignedAngle( Vector3 from, Vector3 to, Vector3 axis ) + { + float unsignedAngle = Vector3.GetAngle( from, to ); + + float cross_x = from.y * to.z - from.z * to.y; + float cross_y = from.z * to.x - from.x * to.z; + float cross_z = from.x * to.y - from.y * to.x; + float sign = MathF.Sign( axis.x * cross_x + axis.y * cross_y + axis.z * cross_z ); + return unsignedAngle * sign; + } + public float VelocityAngle { get; private set; } + public int CarDirection { get { return ForwardSpeed.InchToMeter() < 5 ? 0 : (VelocityAngle < 90 && VelocityAngle > -90 ? 1 : -1); } } private void UpdateSteering( float dt ) { var inputSteer = Input.AnalogMove.y; - var absInputSteer = Math.Abs( inputSteer ); - var sideSlip = Math.Clamp( avgSideSlip, -1, 1 ); + + VelocityAngle = -SignedAngle( Body.Velocity, WorldRotation.Forward, WorldRotation.Up ); var steerConeFactor = Math.Clamp( TotalSpeed / SteerConeMaxSpeed, 0, 1 ); var steerCone = 1 - steerConeFactor * (1 - SteerConeMaxAngle); - steerCone = Math.Clamp( steerCone, Math.Abs( sideSlip ), 1 ); - inputSteer = ExpDecay( this.inputSteer, inputSteer * steerCone, SteerConeChangeRate, dt ); this.inputSteer = inputSteer; - var counterSteer = sideSlip * steerConeFactor * (1 - absInputSteer); - counterSteer = Math.Clamp( counterSteer, -1, 1 ) * CounterSteer; - inputSteer = Math.Clamp( inputSteer + counterSteer, -1, 1 ); + float target = -inputSteer * MaxSteerAngle; + if ( CarDirection > 0 ) + target -= VelocityAngle * CounterSteer; + + inputSteer = Math.Clamp( inputSteer, -1, 1 ); Steering = inputSteer; - SteerAngle = new( 0, -inputSteer * MaxSteerAngle, 0 ); - - if ( ForwardSpeed < -100 ) - jTurnMultiplier = 0.5f; - else - jTurnMultiplier = ExpDecay( jTurnMultiplier, 1, 2, dt ); + SteerAngle = new( 0, target, 0 ); } } diff --git a/Code/Car/VeloXCar.Wheel.cs b/Code/Car/VeloXCar.Wheel.cs index a54f8aa..dbd9ad1 100644 --- a/Code/Car/VeloXCar.Wheel.cs +++ b/Code/Car/VeloXCar.Wheel.cs @@ -2,27 +2,9 @@ public partial class VeloXCar { - private float avgSideSlip; - private float avgPoweredRPM; - private float avgForwardSlip; private void WheelThink( in float dt ) { - float avgRPM = 0, totalSideSlip = 0, totalForwardSlip = 0; - foreach ( var w in Wheels ) - { w.Update( this, dt ); - - totalSideSlip += w.SideSlip; - totalForwardSlip += w.ForwardSlip; - var rpm = w.RPM; - - avgRPM += rpm * w.DistributionFactor; - } - - avgPoweredRPM = avgRPM; - avgSideSlip = totalSideSlip / Wheels.Count; - avgForwardSlip = totalForwardSlip / Wheels.Count; - } } diff --git a/Code/Car/VeloXCar.cs b/Code/Car/VeloXCar.cs index faf7def..e4d7fdf 100644 --- a/Code/Car/VeloXCar.cs +++ b/Code/Car/VeloXCar.cs @@ -7,32 +7,6 @@ namespace VeloX; [Title( "VeloX - Car" )] public partial class VeloXCar : VeloXBase { - protected override void OnStart() - { - base.OnStart(); - //StreamPlayer = new( Stream ); - //if ( IsDriver ) - //{ - // UpdateGearList(); - // UpdatePowerDistribution(); - //} - } - - protected override void OnUpdate() - { - base.OnUpdate(); - //if ( StreamPlayer is not null ) - //{ - - // StreamPlayer.Throttle = Throttle; - // StreamPlayer.RPMPercent = RPMPercent; - // StreamPlayer.EngineState = EngineState; - // StreamPlayer.IsRedlining = IsRedlining; - - // StreamPlayer.Update( Time.Delta, WorldPosition ); - //} - - } protected override void OnFixedUpdate() { if ( !IsDriver ) diff --git a/Editor/Wheel/PacejkaWidget.cs b/Editor/Wheel/PacejkaWidget.cs index 78d194c..37ded7c 100644 --- a/Editor/Wheel/PacejkaWidget.cs +++ b/Editor/Wheel/PacejkaWidget.cs @@ -17,7 +17,7 @@ public class PacejkaWidget : ControlObjectWidget Layout = Layout.Column(); Layout.Margin = 8f; Layout.Spacing = 8; - foreach ( var item in TypeLibrary.GetType().Fields ) + foreach ( var item in TypeLibrary.GetType().Properties ) { var row = Layout.AddRow(); row.Spacing = 8; @@ -36,7 +36,7 @@ public class PacejkaWidget : ControlObjectWidget Layout = Layout.Column(); Layout.Margin = 8f; Layout.Spacing = 8; - foreach ( var item in TypeLibrary.GetType().Fields ) + foreach ( var item in TypeLibrary.GetType().Properties ) { var row = Layout.AddRow(); row.Spacing = 8; @@ -55,7 +55,7 @@ public class PacejkaWidget : ControlObjectWidget Layout = Layout.Column(); Layout.Margin = 8f; Layout.Spacing = 8; - foreach ( var item in TypeLibrary.GetType().Fields ) + foreach ( var item in TypeLibrary.GetType().Properties ) { var row = Layout.AddRow(); row.Spacing = 8; diff --git a/Editor/Wheel/TirePresetPreview.cs b/Editor/Wheel/TirePresetPreview.cs index 2e08a9d..4bf7564 100644 --- a/Editor/Wheel/TirePresetPreview.cs +++ b/Editor/Wheel/TirePresetPreview.cs @@ -1,7 +1,6 @@ using Editor; using Editor.Assets; using Editor.Inspectors; -using Editor.ShaderGraph.Nodes; using Sandbox; using System; using System.Collections.Generic; @@ -68,16 +67,13 @@ class TirePresetPreview( Asset asset ) : PixmapAssetPreview( asset ) for ( float x = x0; x <= xn; x += (xn - x0) / points ) { - float yval = tire.PacejkaFy( x, load, Camber, 1.0f, out float maxforce ) / load; + float yval = tire.PacejkaFy( x, load, Camber, 1.0f, out float _ ) / load; float xval = width * (x - x0) / (xn - x0); yval /= ymax - ymin; yval = (yval + 1.0f) * 0.5f; yval = 1.0f - yval; yval *= height; - if ( x == x0 ) - pointCache.Add( new( xval, yval ) ); - else - pointCache.Add( new( xval, yval ) ); + pointCache.Add( new( xval, yval ) ); } Paint.DrawLine( pointCache ); @@ -86,6 +82,29 @@ class TirePresetPreview( Asset asset ) : PixmapAssetPreview( asset ) { // draw longitudinal line pointCache.Clear(); + Paint.SetPen( Color.Green, 1 ); + float x0 = -zoom * 0.5f; + float xn = zoom * 0.5f; + float ymin = -1000.0f; + float ymax = 1000.0f; + int points = 500; + + for ( float x = x0; x <= xn; x += (xn - x0) / points ) + { + float yval = tire.PacejkaFx( x, load, 1.0f, out var _ ) / load; + float xval = width * (x - x0) / (xn - x0); + yval /= ymax - ymin; + yval = (yval + 1.0f) * 0.5f; + yval = 1.0f - yval; + yval *= height; + pointCache.Add( new( xval, yval ) ); + } + Paint.DrawLine( pointCache ); + } + + { // draw aligning line + pointCache.Clear(); + Paint.SetPen( Color.Blue, 1 ); float x0 = -zoom * 0.5f * 10.0f; float xn = zoom * 0.5f * 10.0f; @@ -101,36 +120,7 @@ class TirePresetPreview( Asset asset ) : PixmapAssetPreview( asset ) yval = (yval + 1.0f) * 0.5f; yval = 1.0f - yval; yval *= height; - if ( x == x0 ) - pointCache.Add( new( xval, yval ) ); - else - pointCache.Add( new( xval, yval ) ); - } - Paint.DrawLine( pointCache ); - } - - { // draw aligning line - pointCache.Clear(); - - Paint.SetPen( Color.Green, 1 ); - float x0 = -zoom * 0.5f; - float xn = zoom * 0.5f; - float ymin = -1000.0f; - float ymax = 1000.0f; - int points = 500; - - for ( float x = x0; x <= xn; x += (xn - x0) / points ) - { - float yval = tire.PacejkaFx( x, load, 1.0f ) / load; - float xval = width * (x - x0) / (xn - x0); - yval /= ymax - ymin; - yval = (yval + 1.0f) * 0.5f; - yval = 1.0f - yval; - yval *= height; - if ( x == x0 ) - pointCache.Add( new( xval, yval ) ); - else - pointCache.Add( new( xval, yval ) ); + pointCache.Add( new( xval, yval ) ); } Paint.DrawLine( pointCache ); }