|
@@ -1,13 +1,23 @@
|
|
|
-using Shaker.Models;
|
|
|
+using Avalonia.Controls;
|
|
|
+using Shaker.Models;
|
|
|
+using ShakerApp.Tools;
|
|
|
using System;
|
|
|
using System.Collections;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Data;
|
|
|
+using System.Diagnostics;
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
using System.Linq;
|
|
|
+using System.Text;
|
|
|
|
|
|
namespace ShakerApp.ViewModels
|
|
|
{
|
|
|
- internal abstract class BaseDataReviewItemViewModel:DisplayViewModelBase<IModel>,IDataReviewItem
|
|
|
+ public abstract class BaseDataReviewItemViewModel:DisplayViewModelBase<IModel>,IDataReviewItem
|
|
|
{
|
|
|
+ public BaseDataReviewItemViewModel()
|
|
|
+ {
|
|
|
+ TimeDomainReview = new TimeDomainReviewViewModel(this);
|
|
|
+ }
|
|
|
private protected ShakerConfigModel ShakerConfig = new ShakerConfigModel();
|
|
|
private protected ShakerControlModel ShakerControl = new ShakerControlModel();
|
|
|
private protected DeviceInfoModel DeviceInfo = new DeviceInfoModel();
|
|
@@ -17,6 +27,8 @@ namespace ShakerApp.ViewModels
|
|
|
public string File { get; } = string.Empty;
|
|
|
[AllowNull]
|
|
|
private protected TDMS.ITDMSFile tdmsfile;
|
|
|
+ [AllowNull]
|
|
|
+ public TimeDomainReviewViewModel TimeDomainReview { get; }
|
|
|
public virtual void OpenFile(string path)
|
|
|
{
|
|
|
tdmsfile?.Close();
|
|
@@ -38,19 +50,19 @@ namespace ShakerApp.ViewModels
|
|
|
if (tdmsfile == null) return;
|
|
|
var group = tdmsfile.Contains(nameof(ShakerConfigModel)) ? tdmsfile[nameof(ShakerConfigModel)] : null;
|
|
|
if (group == null) return;
|
|
|
- GetConfig(ref ShakerConfig, group!);
|
|
|
+ GetConfig(ShakerConfig, group!);
|
|
|
group = tdmsfile.Contains(nameof(ShakerControlModel)) ? tdmsfile[nameof(ShakerControlModel)] : null;
|
|
|
if (group == null) return;
|
|
|
- GetConfig(ref ShakerControl, group!);
|
|
|
+ GetConfig(ShakerControl, group!);
|
|
|
group = tdmsfile.Contains(nameof(DeviceInfoModel)) ? tdmsfile[nameof(DeviceInfoModel)] : null;
|
|
|
if (group == null) return;
|
|
|
- GetConfig(ref DeviceInfo, group!);
|
|
|
+ GetConfig(DeviceInfo, group!);
|
|
|
+ TimeDomainReview.InitData();
|
|
|
}
|
|
|
|
|
|
- private protected void GetConfig<T>(ref T config,TDMS.ITDMSChannelGroup group)
|
|
|
+ private protected void GetConfig<T>(T config,TDMS.ITDMSChannelGroup group)
|
|
|
{
|
|
|
- typeof(T).GetType()
|
|
|
- .GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
|
|
|
+ typeof(T).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
|
|
|
.ToList()
|
|
|
.ForEach(x =>
|
|
|
{
|
|
@@ -63,143 +75,154 @@ namespace ShakerApp.ViewModels
|
|
|
{
|
|
|
bytes[i] = System.Convert.ToByte(val.Substring(i * 2, 2), 16);
|
|
|
}
|
|
|
- x.SetValue(MessagePack.MessagePackSerializer.Deserialize(x.FieldType, bytes), ShakerConfig);
|
|
|
+ x.SetValue(config,ShakerApp.Tools.Tools.Deserialize(x.FieldType, bytes));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue(Activator.CreateInstance(x.FieldType), ShakerConfig);
|
|
|
+ x.SetValue(config,Activator.CreateInstance(x.FieldType));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if(x.FieldType == typeof(string))
|
|
|
+ {
|
|
|
+ if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val))
|
|
|
+ {
|
|
|
+ x.SetValue(config,val);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ x.SetValue(config,string.Empty);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType.IsEnum)
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val))
|
|
|
{
|
|
|
- x.SetValue(Enum.Parse(x.FieldType, val), ShakerConfig);
|
|
|
+ x.SetValue(config,Enum.Parse(x.FieldType, val));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue(Enum.GetValues(x.FieldType), ShakerConfig);
|
|
|
+ x.SetValue(config,Enum.GetValues(x.FieldType));
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(byte))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && byte.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((byte)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(byte)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(sbyte))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && sbyte.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((sbyte)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(sbyte)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(short))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && short.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((short)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(short)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(ushort))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && ushort.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((ushort)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(ushort)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(int))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && int.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((int)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(int)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(uint))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && uint.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((uint)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(uint)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(long))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && long.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((long)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(long)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(ulong))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && ulong.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((ulong)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(ulong)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(float))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && float.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((float)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(float)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(double))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && double.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue((double)0, ShakerConfig);
|
|
|
+ x.SetValue(config,(double)0);
|
|
|
}
|
|
|
}
|
|
|
else if (x.FieldType == typeof(bool))
|
|
|
{
|
|
|
if (group.TryGetProperty<string>(x.Name, out var val) && !string.IsNullOrEmpty(val) && bool.TryParse(val, out var b))
|
|
|
{
|
|
|
- x.SetValue(b, ShakerConfig);
|
|
|
+ x.SetValue(config,b);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x.SetValue(false, ShakerConfig);
|
|
|
+ x.SetValue(config,false);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
@@ -210,5 +233,147 @@ namespace ShakerApp.ViewModels
|
|
|
tdmsfile?.Dispose();
|
|
|
tdmsfile = null;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public class TimeDomainReviewViewModel : DisplayViewModelBase<IModel>
|
|
|
+ {
|
|
|
+ private bool isinint = false;
|
|
|
+ List<OxyPlot.Series.LineSeries> _LineSeries = new List<OxyPlot.Series.LineSeries>();
|
|
|
+ public OxyPlot.PlotModel PlotModel { get; } = new OxyPlot.PlotModel();
|
|
|
+ private BaseDataReviewItemViewModel _Parent;
|
|
|
+ public uint SampleRate { get => sampleRate; set =>SetProperty(ref sampleRate , value); }
|
|
|
+ public uint TotalPages
|
|
|
+ {
|
|
|
+ get => Math.Clamp(totalPages, 1, uint.MaxValue);
|
|
|
+ set
|
|
|
+ {
|
|
|
+ SetProperty(ref totalPages, value);
|
|
|
+ OnPropertyChanged(nameof(MaxPageIndex));
|
|
|
+ OnPropertyChanged(nameof(MaxReadPages));
|
|
|
+ OnPropertyChanged(nameof(PageIndex));
|
|
|
+ OnPropertyChanged(nameof(ReadPages));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public uint PageIndex
|
|
|
+ {
|
|
|
+ get =>Math.Clamp(pageIndex,MinPageIndex,MaxPageIndex);
|
|
|
+ set
|
|
|
+ {
|
|
|
+ SetProperty(ref pageIndex, value);
|
|
|
+ OnPropertyChanged(nameof(MaxReadPages));
|
|
|
+ OnPropertyChanged(nameof(ReadPages));
|
|
|
+ LoadData();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public uint MinPageIndex => 1;
|
|
|
+ public uint MaxPageIndex => TotalPages;
|
|
|
+ public uint ReadPages
|
|
|
+ {
|
|
|
+ get =>Math.Clamp(readPages,MinReadPages,MaxReadPages);
|
|
|
+ set
|
|
|
+ {
|
|
|
+ SetProperty(ref readPages, value);
|
|
|
+ LoadData();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public uint MinReadPages => 1;
|
|
|
+ public uint MaxReadPages => Math.Clamp(TotalPages - PageIndex + 1, 1, 10000);
|
|
|
+ public TimeDomainReviewViewModel(BaseDataReviewItemViewModel parent)
|
|
|
+ {
|
|
|
+ _Parent = parent;
|
|
|
+ PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis()
|
|
|
+ {
|
|
|
+ Position = OxyPlot.Axes.AxisPosition.Bottom,
|
|
|
+ Key = "X",
|
|
|
+ Title = App.Current?.FindResource("Time") +"",
|
|
|
+ Unit = "s",
|
|
|
+ MinimumPadding = 0,
|
|
|
+ MaximumPadding = 0,
|
|
|
+ });
|
|
|
+ PlotModel.Axes.Add(new OxyPlot.Axes.LinearAxis()
|
|
|
+ {
|
|
|
+ Position = OxyPlot.Axes.AxisPosition.Left,
|
|
|
+ Key = "Y",
|
|
|
+ Title = App.Current?.FindResource("")+"",
|
|
|
+ MinimumPadding = 0,
|
|
|
+ MaximumPadding = 0,
|
|
|
+ });
|
|
|
+ PlotModel.Legends.Add(new OxyPlot.Legends.Legend()
|
|
|
+ {
|
|
|
+ IsLegendVisible = true,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ private TDMS.ITDMSChannelGroup? _DataGroup;
|
|
|
+ private List<TDMS.ITDMSChannel> _Channels = new List<TDMS.ITDMSChannel>();
|
|
|
+ private uint readPages;
|
|
|
+ private uint pageIndex;
|
|
|
+ private uint totalPages;
|
|
|
+ private uint sampleRate;
|
|
|
+
|
|
|
+ public override void InitData()
|
|
|
+ {
|
|
|
+ isinint = false;
|
|
|
+ base.InitData();
|
|
|
+ _DataGroup = _Parent.tdmsfile.Contains(BaseMainPageViewModel<IModel>.TimeDomainData) ? _Parent.tdmsfile[BaseMainPageViewModel<IModel>.TimeDomainData] : null;
|
|
|
+ if (_DataGroup == null)
|
|
|
+ {
|
|
|
+ DataReviewViewModel.Instance.ShowError(App.Current?.FindResource("TestFileReadError")+"");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _Channels.Clear();
|
|
|
+ _LineSeries.Clear();
|
|
|
+ PlotModel.Series.Clear();
|
|
|
+ if(_DataGroup.ChildCount ==0)
|
|
|
+ {
|
|
|
+ DataReviewViewModel.Instance.ShowError(App.Current?.FindResource("TestFileReadError") + "");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ PlotModel.InvalidatePlot(false);
|
|
|
+ for(ulong i=0;i<_DataGroup.ChildCount;i++)
|
|
|
+ {
|
|
|
+ _Channels.Add(_DataGroup[(int)i]!);
|
|
|
+ _LineSeries.Add(new OxyPlot.Series.LineSeries()
|
|
|
+ {
|
|
|
+ XAxisKey = "X",
|
|
|
+ YAxisKey = "Y",
|
|
|
+ DataFieldX = nameof(OxyPlot.DataPoint.X),
|
|
|
+ DataFieldY = nameof(OxyPlot.DataPoint.Y),
|
|
|
+ Title = App.Current?.FindResource(_Channels[^1].Name)+"",
|
|
|
+ Tag = _Channels[^1].Unit,
|
|
|
+ });
|
|
|
+ PlotModel.Series.Add(_LineSeries[^1]);
|
|
|
+ }
|
|
|
+ PlotModel.InvalidatePlot(true);
|
|
|
+ SampleRate = _Parent.ShakerConfig.SampleRate;
|
|
|
+ TotalPages = (uint)Math.Ceiling(_Channels[0].ChildCount / (double)SampleRate);
|
|
|
+ ReadPages = 1;
|
|
|
+ PageIndex = 1;
|
|
|
+ isinint = true;
|
|
|
+ LoadData();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void LoadData()
|
|
|
+ {
|
|
|
+ if (!isinint) return;
|
|
|
+ uint start = (PageIndex - 1) * SampleRate;
|
|
|
+ uint len = ReadPages * SampleRate;
|
|
|
+ len = (uint)Math.Clamp(len, len, _Channels[^1].ChildCount - start);
|
|
|
+ double pro = 1d / SampleRate;
|
|
|
+ //var datas = Enumerable.Repeat(new OxyPlot.DataPoint(), 1000_000).ToList();
|
|
|
+ PlotModel.InvalidatePlot(false);
|
|
|
+
|
|
|
+ for(int i=0;i<_Channels.Count;i++)
|
|
|
+ {
|
|
|
+ uint index = 0;
|
|
|
+ _LineSeries[i].ItemsSource = _Channels[i].GetDataValues<double>(start, len).Select(x =>
|
|
|
+ {
|
|
|
+ return new OxyPlot.DataPoint((index++) * pro, x);
|
|
|
+ }).ToList();
|
|
|
+ // _LineSeries[i].ItemsSource = datas;
|
|
|
+ }
|
|
|
+ PlotModel.InvalidatePlot(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|