new pacejka implementation (car not working)

This commit is contained in:
Valera
2025-06-14 18:16:26 +07:00
parent 964b46e1c5
commit 629ae6715c
14 changed files with 883 additions and 283 deletions

View File

@@ -1,55 +0,0 @@
//using Editor;
//using Editor.Assets;
//using Sandbox;
//using VeloX;
//using static Editor.Inspectors.AssetInspector;
//[CanEdit( "asset:engstr" )]
//public class EngineStreamInspector : Widget, IAssetInspector
//{
// EngineStream EngineStream;
// ControlSheet MainSheet;
// public EngineStreamInspector( Widget parent ) : base( parent )
// {
// Layout = Layout.Column();
// Layout.Margin = 12;
// Layout.Spacing = 12;
// MainSheet = new ControlSheet();
// Layout.Add( MainSheet, 1 );
// }
// [EditorEvent.Hotload]
// void RebuildSheet()
// {
// if ( EngineStream is null || MainSheet is null )
// return;
// Layout.Clear( true );
// var text = Layout.Add( new Editor.TextEdit() );
// var but = Layout.Add( new Editor.Button( "Load JSON" ) );
// but.Clicked += () =>
// {
// EngineStream.LoadFromJson( text.PlainText );
// };
// var so = EngineStream.GetSerialized();
// so.OnPropertyChanged += _ =>
// {
// EngineStream.StateHasChanged();
// };
// Layout.Add( ControlWidget.Create( so.GetProperty( nameof( EngineStream.Layers ) ) ) );
// Layout.Add( ControlWidget.Create( so.GetProperty( nameof( EngineStream.Parameters ) ) ) );
// }
// public void SetAsset( Asset asset )
// {
// EngineStream = asset.LoadResource<EngineStream>();
// RebuildSheet();
// }
//}

View File

@@ -0,0 +1,90 @@
using Editor;
using Sandbox;
namespace VeloX;
[CustomEditor( typeof( Pacejka ) )]
public class PacejkaWidget : ControlObjectWidget
{
public override bool SupportsMultiEdit => false;
public override bool IncludeLabel => false;
[CustomEditor( typeof( Pacejka.LateralForce ) )]
private class LateralForceWidget : ControlObjectWidget
{
public LateralForceWidget( SerializedProperty property ) : base( property, true )
{
Layout = Layout.Column();
Layout.Margin = 8f;
Layout.Spacing = 8;
foreach ( var item in TypeLibrary.GetType<Pacejka.LateralForce>().Fields )
{
var row = Layout.AddRow();
row.Spacing = 8;
var propetry = SerializedObject.GetProperty( item.Name );
row.Add( new Label( propetry.Name ) );
row.Add( Create( propetry ) );
}
}
}
[CustomEditor( typeof( Pacejka.LongitudinalForce ) )]
private class LongitudinalForceWidget : ControlObjectWidget
{
public LongitudinalForceWidget( SerializedProperty property ) : base( property, true )
{
Layout = Layout.Column();
Layout.Margin = 8f;
Layout.Spacing = 8;
foreach ( var item in TypeLibrary.GetType<Pacejka.LongitudinalForce>().Fields )
{
var row = Layout.AddRow();
row.Spacing = 8;
var propetry = SerializedObject.GetProperty( item.Name );
row.Add( new Label( propetry.Name ) );
row.Add( Create( propetry ) );
}
}
}
[CustomEditor( typeof( Pacejka.AligningMoment ) )]
private class AligningMomentWidget : ControlObjectWidget
{
public AligningMomentWidget( SerializedProperty property ) : base( property, true )
{
Layout = Layout.Column();
Layout.Margin = 8f;
Layout.Spacing = 8;
foreach ( var item in TypeLibrary.GetType<Pacejka.AligningMoment>().Fields )
{
var row = Layout.AddRow();
row.Spacing = 8;
var propetry = SerializedObject.GetProperty( item.Name );
row.Add( new Label( propetry.Name ) );
row.Add( Create( propetry ) );
}
}
}
private Pacejka Pacejka;
public PacejkaWidget( SerializedProperty property ) : base( property, true )
{
var obj = SerializedObject;
Pacejka = obj.ParentProperty.GetValue<Pacejka>();
Layout = Layout.Column();
Layout.Margin = 8f;
Layout.Add( new Label.Body( $" {ToolTip}" ) { Color = Color.White } );
var tabs = Layout.Add( new TabWidget( null ) );
tabs.AddPage( nameof( Pacejka.Lateral ), null,
Layout.Add( Create( obj.GetProperty( nameof( Pacejka.Lateral ) ) ) )
);
tabs.AddPage( nameof( Pacejka.Longitudinal ), null,
Layout.Add( Create( obj.GetProperty( nameof( Pacejka.Longitudinal ) ) ) )
);
tabs.AddPage( nameof( Pacejka.Aligning ), null,
Layout.Add( Create( obj.GetProperty( nameof( Pacejka.Aligning ) ) ) )
);
}
}

View File

@@ -0,0 +1,70 @@
using Editor;
using Editor.Assets;
using Editor.Inspectors;
using Sandbox;
using static Editor.Inspectors.AssetInspector;
namespace VeloX;
[CanEdit( "asset:tire" )]
public class TirePresetEditor : Widget, IAssetInspector
{
TirePreset Tire;
ControlSheet MainSheet;
TirePresetPreview TirePreview;
public TirePresetEditor( Widget parent ) : base( parent )
{
Layout = Layout.Column();
Layout.Margin = 4;
Layout.Spacing = 4;
// Create a ontrolSheet that will display all our Properties
MainSheet = new ControlSheet();
Layout.Add( MainSheet );
//// Add a randomize button below the ControlSheet
//var button = Layout.Add( new Button( "Randomize", "casino", this ) );
//button.Clicked += () =>
//{
// foreach ( var prop in Test.GetSerialized() )
// {
// // Randomize all the float values from 0-100
// if ( prop.PropertyType != typeof( float ) ) continue;
// prop.SetValue( Random.Shared.Float( 0, 100 ) );
// }
//};
Layout.AddStretchCell();
RebuildSheet();
Focus();
}
[EditorEvent.Hotload]
void RebuildSheet()
{
if ( Tire is null ) return;
if ( MainSheet is null ) return;
MainSheet.Clear( true );
var so = Tire.GetSerialized();
so.OnPropertyChanged += x =>
{
Tire.StateHasChanged();
TirePreview.Widget.UpdatePixmap();
};
MainSheet.AddObject( so );
}
void IAssetInspector.SetAssetPreview( AssetPreview preview )
{
TirePreview = preview as TirePresetPreview;
}
public void SetAsset( Asset asset )
{
Tire = asset.LoadResource<TirePreset>();
RebuildSheet();
}
}

View File

@@ -0,0 +1,188 @@
using Editor;
using Editor.Assets;
using Editor.Inspectors;
using Editor.ShaderGraph.Nodes;
using Sandbox;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace VeloX;
[AssetPreview( "tire" )]
class TirePresetPreview( Asset asset ) : PixmapAssetPreview( asset )
{
private TirePreset Tire = asset.LoadResource<TirePreset>();
public AssetPreviewWidget Widget { get; private set; }
[Range( 100, 10000 )] private float Load { get; set; } = 2500f;
[Range( 0, 1 )] private float Zoom { get; set; } = 0;
[Range( -10, 10 )] private float Camber { get; set; } = 0;
public override Widget CreateWidget( Widget parent )
{
Widget = parent as AssetPreviewWidget;
Task.Run( async () =>
{
while ( Widget != null )
{
await MainThread.Wait();
await Widget.UpdatePixmap();
await Task.Delay( 100 );
}
} );
return null;
}
public override Widget CreateToolbar()
{
var info = new IconButton( "settings" );
info.Layout = Layout.Row();
info.MinimumSize = 16;
info.MouseLeftPress = () => OpenSettings( info );
return info;
}
static List<Vector2> pointCache = [];
private void DrawPacejka()
{
float load = Load * 0.001f;
float zoom = (1.0f - Zoom) * 4.0f + 0.1f;
var tire = Tire.Pacejka;
var width = Paint.LocalRect.Width;
var height = Paint.LocalRect.Height;
{ // draw lateral line
pointCache.Clear();
Paint.SetPen( Color.Red, 1 );
float x0 = -zoom * 0.5f * 20.0f;
float xn = zoom * 0.5f * 20.0f;
float ymin = -1000.0f;
float ymax = 1000.0f;
int points = 500;
for ( float x = x0; x <= xn; x += (xn - x0) / points )
{
float yval = tire.PacejkaFy( x, load, Camber, 1.0f, out float maxforce ) / 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 ) );
}
Paint.DrawLine( pointCache );
}
{ // draw longitudinal line
pointCache.Clear();
Paint.SetPen( Color.Blue, 1 );
float x0 = -zoom * 0.5f * 10.0f;
float xn = zoom * 0.5f * 10.0f;
float ymin = -60.0f;
float ymax = 60.0f;
int points = 500;
for ( float x = x0; x <= xn; x += (xn - x0) / points )
{
float yval = tire.PacejkaMz( x, load, Camber * (180.0f / MathF.PI), 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 ) );
}
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 ) );
}
Paint.DrawLine( pointCache );
}
pointCache.Clear();
}
public override Task RenderToPixmap( Pixmap pixmap )
{
Paint.ToPixmap( pixmap );
Paint.Antialiasing = true;
Paint.SetBrush( Color.Gray );
Paint.DrawRect( Paint.LocalRect );
Paint.ClearBrush();
Paint.SetPen( Color.Black, 1 );
var width = Paint.LocalRect.Width;
var height = Paint.LocalRect.Height;
float xc = width / 2;
float yc = height / 2;
Paint.DrawLine( new( xc, 0 ), new( xc, yc * 2 ) );
Paint.DrawLine( new( 0, yc ), new( xc * 2, yc ) );
DrawPacejka();
return Task.CompletedTask;
}
public void OpenSettings( Widget parent )
{
var popup = new PopupWidget( parent )
{
IsPopup = true,
Layout = Layout.Column()
};
popup.Layout.Margin = 16;
var ps = new ControlSheet();
ps.AddProperty( this, x => x.Load );
ps.AddProperty( this, x => x.Zoom );
ps.AddProperty( this, x => x.Camber );
popup.Layout.Add( ps );
popup.MaximumWidth = 300;
popup.Show();
popup.Position = parent.ScreenRect.TopRight - popup.Size;
popup.ConstrainToScreen();
}
}