using Arction.Wpf.Charting; using Arction.Wpf.Charting.Axes; using Arction.Wpf.Charting.SeriesXY; using Arction.Wpf.Charting.Views.ViewXY; using Microsoft.Win32; using mseedChart.Core; using mseedChart.MainModule.Models; using Prism.Commands; using Prism.Events; using Prism.Mvvm; using SharpDX.DirectWrite; using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http.Headers; using System.Reflection; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; namespace mseedChart.MainModule.ViewModels { public class ChartPlotViewModel : BindableBase { public ChartPlotViewModel() { _dispatcher = Application.Current.Dispatcher; _wavesModel = new WavesModel(); CreateChart(); (Application.Current.MainWindow as System.Windows.Window).Closing += ApplicationClosingDispose; string fileName = "2023-03-28T05:14:59.108464"; // fileName = "2023-03-24T04:53:46.199584"; bool multFlies = false; string eventTimeStr = fileName; string datePath = eventTimeStr.Substring(0, 4) + eventTimeStr.Substring(5, 2) + eventTimeStr.Substring(8, 2); string dataFilePath = RegionNames.MseedFilePath + "\\" + datePath + "\\"; string dataFileName = "HA." + eventTimeStr.Substring(0, 4) + eventTimeStr.Substring(5, 2) + eventTimeStr.Substring(8, 2) + eventTimeStr.Substring(10, 3) + eventTimeStr.Substring(14, 2) + eventTimeStr.Substring(17, 2) + ".01" + RegionNames.DataTypeString; string jsonStr = ".json"; string mseedStr = ".mseed"; string asciiSavePath = RegionNames.TxtFilePath + "\\" + datePath + "\\"; if (!multFlies) { CurrentEventTime = _wavesModel.mseedJsonResolve(dataFilePath + dataFileName + jsonStr); } ShowWave(dataFilePath + dataFileName + mseedStr, asciiSavePath + dataFileName + ".txt" , multFlies); YaxisItems.Add("SHZ"); YaxisItems.Add("SHN"); YaxisItems.Add("SHE"); } #region 字段 Dispatcher _dispatcher; public int CurPoints; int _channelCount = 0; double _samplingFrequency = 500; // 采样频率 (Hz). WavesModel _wavesModel; private int _lChartCount = 1; public ConcurrentQueue smList; #endregion #region 属性 private List _yaxisItems=new List(); public List YaxisItems { get { return _yaxisItems; } set { _yaxisItems = value; } } private int _selectIndex=1; public int SelectIndex { get { return _selectIndex; } set { SetProperty(ref _selectIndex, value); } } private bool _isMultFiles; public bool IsMultFiles { get { return _isMultFiles; } set { SetProperty(ref _isMultFiles, value); } } private int _xaisInterval; public int XaisInterval { get { return _xaisInterval; } set { SetProperty(ref _xaisInterval, value); } } /// /// 波形控件数量 /// public int LChartCount { get { return _lChartCount; } set { _lChartCount = value; } } private LightningChart _lChartAll; /// /// 所有波形 /// public LightningChart LChartALL { get { return _lChartAll; } set { _lChartAll = value; } } private FrameworkElement childContent; public FrameworkElement ChildContent { get { return childContent; } set { childContent = value; } } private Grid gridChart; public Grid GridChart { get { return gridChart; } set { gridChart = value; } } private StationEventJson _currentEventTime; public StationEventJson CurrentEventTime { get { return _currentEventTime; } set { _currentEventTime = value; } } #endregion #region 事件 public DelegateCommand AxesYVisibleCommand => new DelegateCommand(AxesYVisible); public DelegateCommand FileSelectorCommand => new DelegateCommand(FileSelector); public DelegateCommand OtimeSortCommand => new DelegateCommand(OtimeSort); public DelegateCommand YasixZENVisibleCommand => new DelegateCommand(YasixZENVisible); public DelegateCommand IntervalSureCommand => new DelegateCommand(IntervalSure); private void AxesYVisible(object isCheck) { if (_lChartAll != null) { bool yAxesVisible = ((bool)isCheck == true); _lChartAll.BeginUpdate(); AxisY lastYAxis = _lChartAll.ViewXY.YAxes.Last(); _lChartAll.ViewXY.AxisLayout.AutoAdjustMargins = false; foreach (AxisY yAxis in _lChartAll.ViewXY.YAxes) { if (yAxis != lastYAxis) { yAxis.Visible = yAxesVisible; } else { yAxis.Visible = true; yAxis.LabelsVisible = yAxesVisible; //yAxis.MajorDivTickStyle.Visible = yAxesVisible; //yAxis.MinorDivTickStyle.Visible = yAxesVisible; yAxis.Title.Visible = yAxesVisible; if (yAxesVisible) { yAxis.AxisThickness = 3; } else { yAxis.AxisThickness = 0; } // lastYAxis.MiniScale.Visible = !yAxesVisible; } } _lChartAll.EndUpdate(); } } private void FileSelector() { OpenFileDialog openFileDialog = new OpenFileDialog { RestoreDirectory = true, Filter = ".mseed|*.mseed|.json|*.json|.txt|*.txt", }; if (openFileDialog.ShowDialog() == true) { string asciiSavePath = openFileDialog.FileName; asciiSavePath = asciiSavePath.Replace("Mseed","Txt"); asciiSavePath= Path.ChangeExtension(asciiSavePath, ".txt"); ShowWave(openFileDialog.FileName, asciiSavePath, IsMultFiles); } } private void OtimeSort(object isCheck) { if (_lChartAll != null) { LChartALL.BeginUpdate(); bool yAxesVisible = ((bool)isCheck == true); ViewXY v= _lChartAll.ViewXY; IOrderedEnumerable lines; if (yAxesVisible) { lines = v.LineCollections.Where(a => a.Tag != null && a.Tag.ToString().Contains("SHZ")).OrderBy(a => a.Lines[0].AX); } else { lines = v.LineCollections.Where(a => a.Tag != null && a.Tag.ToString().Contains("SHZ")).OrderByDescending(b => b.Lines[0].AX); ; } foreach (var item in lines) { var a= item.Tag.ToString().Contains("SHZ"); } foreach (var item in lines.Reverse()) { int index = item.AssignYAxisIndex; for (int i = 0; i < 3; i++) { AxisY axisY = v.YAxes[index + i]; v.YAxes.RemoveAt(index + i); v.YAxes.Insert(i, axisY); } } LChartALL.EndUpdate(); } } private void YasixZENVisible(object isCheck) { if (_lChartAll != null) { _lChartAll.BeginUpdate(); bool yAxesVisible = ((bool)isCheck == true); ViewXY v = _lChartAll.ViewXY; List indexs = new List(); switch (SelectIndex) { case 0: indexs = v.YAxes.Select(a => a.Title.Text.Contains(".Z")).ToList(); break; case 1: indexs = v.YAxes.Select(a => a.Title.Text.Contains(".N")).ToList(); break; case 2: indexs = v.YAxes.Select(a => a.Title.Text.Contains(".E")).ToList(); break; default: break; } for (int i = 0; i < indexs.Count; i++) { if (indexs[i] == true) { AxisY axisY = v.YAxes[i]; axisY.Visible = !yAxesVisible; v.SampleDataSeries[i].Visible = !yAxesVisible; int index = v.LineCollections.FindIndex(a => a.AssignYAxisIndex == i); if (index != -1) { v.LineCollections[index].Visible = !yAxesVisible; } } } _lChartAll.EndUpdate(); } } private void IntervalSure() { if (_lChartAll != null) { _lChartAll.BeginUpdate(); if (XaisInterval >= 2) { _lChartAll.ViewXY.XAxes[0].MajorDivCount = XaisInterval; } _lChartAll.EndUpdate(); } } #endregion public List UpdateWavesFromTxt(string fn) { string allStr; List temSM = new List(); using (StreamReader streamReader = new StreamReader(fn)) { allStr = streamReader.ReadToEnd(); } if (allStr.Length > 0) { string[] strLines = allStr.Trim().Split(new char[] { '\n' }); List strList = strLines.ToList(); int cnt = strList.Count; string[] snStr = strLines[0].Trim().Split(','); string tmpName = snStr[0].Substring(14, 3); CurPoints = int.Parse(snStr[1].Trim().Split(' ')[0]); StationModel station = new StationModel(); station.Name = tmpName; int channelFlag = 0; for (int i = 0; i < strLines.Length; i++) { string row = strLines[i].Trim(); if (strLines[i].Contains("HA")) { string[] rowStr = strLines[i].Split(','); string chnStr1 = rowStr[0].Substring(21, 3); string stationName = rowStr[0].Substring(14, 3); if (!temSM.Any(name => name.Name == stationName)) { station = new StationModel(); station.Name = stationName; station.BeginTime =Convert.ToDateTime(rowStr[3]); station.PointCount = int.Parse(rowStr[1].Trim().Split(' ')[0]); station.SamplingFrequency = int.Parse(rowStr[2].Trim().Split(' ')[0]); temSM.Add(station); } if (chnStr1 == "SHZ") { channelFlag = 0;//Z } else if (chnStr1 == "SHN") { channelFlag = 1;//N } else { channelFlag = 2;//E } } else { switch (channelFlag) { case 0://Z station.dz.Add(double.Parse(row)); break; case 1://N station.dn.Add(double.Parse(row)); break; case 2://E station.de.Add(double.Parse(row)); break; } } } // temSM.Add(station); temSM.Reverse(); } return temSM; } public void MSeed2Asc(string filePath, string savePath) { using (Process compiler = new Process()) { compiler.StartInfo.FileName = "mseed2ascii.exe"; compiler.StartInfo.Arguments = filePath + " -o " + savePath; compiler.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; compiler.StartInfo.CreateNoWindow = true; compiler.Start(); compiler.WaitForExit(); } } private void CreateChart() { if (LChartALL != null) { LChartALL = null; } LChartALL = new LightningChart(); LChartALL.Title.Align = ChartTitleAlignment.TopCenter; LChartALL.ChartRenderOptions.DeviceType = RendererDeviceType.AutoPreferD11; LChartALL.ChartRenderOptions.LineAAType2D = LineAntiAliasingType.QLAA; LChartALL.Title.Text = "事件波形"; LChartALL.Title.Font = new WpfFont("等线", 20); //轴属性和布局 LChartALL.ViewXY.AxisLayout.YAxesLayout = YAxesLayout.Stacked; LChartALL.ViewXY.AxisLayout.SegmentsGap = 0; LChartALL.ViewXY.ZoomPanOptions.PanDirection = PanDirection.Horizontal; LChartALL.ViewXY.ZoomPanOptions.WheelZooming = WheelZooming.Horizontal; LChartALL.ViewXY.AxisLayout.YAxisAutoPlacement = YAxisAutoPlacement.AllLeft; LChartALL.ViewXY.AxisLayout.YAxisTitleAutoPlacement = true; LChartALL.ViewXY.AxisLayout.AutoAdjustMargins = false; LChartALL.ViewXY.ZoomPanOptions.DevicePrimaryButtonAction = UserInteractiveDeviceButtonAction.None; LChartALL.ViewXY.ZoomPanOptions.DeviceSecondaryButtonAction = UserInteractiveDeviceButtonAction.None; LChartALL.ViewXY.ZoomPanOptions.WheelZooming = WheelZooming.Off; // 反锯齿系数。值0和1都不会应用反锯齿 LChartALL.ChartRenderOptions.AntiAliasLevel = 0; //X轴设置 LChartALL.ViewXY.XAxes[0].AllowScrolling = false; LChartALL.ViewXY.XAxes[0].PanningEnabled = false; LChartALL.ViewXY.XAxes[0].MajorGrid.Pattern = LinePattern.Solid; LChartALL.ViewXY.XAxes[0].ValueType = AxisValueType.DateTime; LChartALL.ViewXY.XAxes[0].KeepDivCountOnRangeChange = true; //LChartALL.ViewXY.XAxes[0].MajorDiv =6; LChartALL.ViewXY.XAxes[0].LabelsColor = Colors.Black; LChartALL.ViewXY.XAxes[0].AutoDivSpacing = false; LChartALL.ViewXY.XAxes[0].MajorDivCount = 5; XaisInterval = 5; //图表背景颜色 LChartALL.ViewXY.GraphBackground.Color = Colors.White; LChartALL.ViewXY.GraphBackground.GradientColor = Colors.White; LChartALL.ChartBackground.GradientFill = GradientFill.Solid; LChartALL.ChartBackground.Color = Color.FromArgb(0, 0, 0, 0); GridChart = new Grid(); GridChart.ColumnDefinitions.Add(new ColumnDefinition()); GridChart.Name = "chartGrid"; GridChart.Children.Add(LChartALL); this.ChildContent = GridChart; } private void ShowWave(string dataFilePath, string asciiSavePath, bool isMultFile = false) { if (!Directory.Exists(Path.GetDirectoryName(dataFilePath))) { Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); } if (!Directory.Exists(Path.GetDirectoryName(asciiSavePath))) { Directory.CreateDirectory(Path.GetDirectoryName(asciiSavePath)); } smList = new ConcurrentQueue(); if (isMultFile) { var filePath = new DirectoryInfo(Path.GetDirectoryName(dataFilePath)); FileInfo[] files = filePath.GetFiles(); var mseedFiles = files.Where(i => i.Extension == ".mseed"); var asciiFiles = new DirectoryInfo(Path.GetDirectoryName(asciiSavePath)); var asciifile = asciiFiles.GetFiles(); if (asciifile.Count()==0) { // 并行运算 Stopwatch sw = Stopwatch.StartNew(); Parallel.ForEach(mseedFiles, (item) => { MSeed2Asc(item.FullName, Path.Combine(Path.GetDirectoryName(asciiSavePath), Path.GetFileNameWithoutExtension(item.Name))); }); sw.Stop(); Debug.WriteLine("MSeed2Asc解压时间:" +sw.Elapsed.TotalSeconds); } // 并行运算 Parallel.ForEach(asciiFiles.GetFiles(), (item) => { var list = UpdateWavesFromTxt(item.FullName); list.ForEach(i => smList.Enqueue(i)); }); } else { if (!File.Exists(asciiSavePath)) { MSeed2Asc(dataFilePath, asciiSavePath); } var list = UpdateWavesFromTxt(asciiSavePath); list.ForEach(i => smList.Enqueue(i)); } _channelCount = smList.Count * 3; UpdateChart(); UpdateChartData(); } private void UpdateChart() { ViewXY v= LChartALL.ViewXY; DisposeAllAndClear(v.YAxes); DisposeAllAndClear(v.SampleDataSeries); DisposeAllAndClear(v.LineCollections); v.YAxes.AddRange(_wavesModel.CreateYAxisChart(smList.ToList(), LChartALL)); v.LegendBoxes[0].Position = LegendBoxPositionXY.RightCenter; v.LegendBoxes[0].Offset.SetValues(-10, 180); v.LegendBoxes[0].Layout = LegendBoxLayout.Vertical; v.LegendBoxes[0].Visible = false; v.AutoSpaceLegendBoxes = true; v.AxisLayout.SegmentsGap = 3; v.LegendBoxes[0].Shadow.Visible =false; StationModel stationModel = smList.ElementAt(0); if (AxisValueType.DateTime == v.XAxes[0].ValueType) { //设置X轴的开始时间 v.XAxes[0].AutoFormatLabels = false; v.XAxes[0].LabelsTimeFormat = "HH:mm:ss.ff"; v.XAxes[0].DateOriginYear = CurrentEventTime.otime.Year; v.XAxes[0].DateOriginDay = CurrentEventTime.otime.Day; v.XAxes[0].DateOriginMonth = CurrentEventTime.otime.Month; DateTime MaxDateTime = CurrentEventTime.otime.AddSeconds(_samplingFrequency == 500 ? 30 : 60); v.XAxes[0].SetRange(v.XAxes[0].DateTimeToAxisValue(CurrentEventTime.otime), v.XAxes[0].DateTimeToAxisValue(MaxDateTime)); } double firstSampleTimeStamp = v.XAxes[0].DateTimeToAxisValue(CurrentEventTime.otime); for (int i = 0; i < smList.Count; i++) { for (int k = 0; k < smList.ElementAt(i).Dzne.Count; k++) { int seriesIndex = i * 3 + k; AxisY axisY= v.YAxes[seriesIndex]; axisY.LabelsColor = Colors.Black; axisY.Title.Shadow.DropColor = Colors.Transparent; axisY.Title.Shadow.ContrastColor = Colors.Transparent; axisY.AllowAutoYFit = false; axisY.Units.Visible = false; axisY.LabelsAngle = 0; axisY.LabelsFont.Size = 8; axisY.Title.Angle = 0; axisY.MajorGrid.Visible = true; axisY.MinorGrid.Visible = false; axisY.MajorGrid.Pattern = LinePattern.Solid; axisY.AutoDivSpacing = false; // axisY.AutoDivSeparationPercent = 100; axisY.Visible = true; axisY.MajorDivCount = 2; axisY.MajorDivTickStyle.Visible = true; axisY.MinorDivTickStyle.Visible = false; axisY.MajorDivTickStyle.Alignment = seriesIndex % 2 == 0 ? Alignment.Near : Alignment.Far; axisY.MajorDivTickStyle.LineLength = 6; axisY.MajorDivTickStyle.Color = Colors.Black; axisY.Title.Color = Colors.Black; axisY.Title.Font = new WpfFont("Segoe UI", 10, false, false); axisY.PanningEnabled = false; axisY.AllowScrolling = false; axisY.AllowScaling = false; SampleDataSeries series = new SampleDataSeries(v, v.XAxes[0], axisY); series.ShowInLegendBox = true; series.FirstSampleTimeStamp = firstSampleTimeStamp; series.SamplingFrequency = _samplingFrequency; series.Title.Text = axisY.Title.Text; series.SampleFormat = SampleFormat.DoubleFloat; if (k % 3 == 0) { series.LineStyle.Color = System.Windows.Media.Colors.Blue; } else if (k % 3 == 1) { series.LineStyle.Color = System.Windows.Media.Colors.Red; } else if (k % 3 == 2) { series.LineStyle.Color = System.Windows.Media.Colors.Green; } series.LineStyle.Width =0.5; series.LineStyle.AntiAliasing = LineAntialias.None; series.ScrollModePointsKeepLevel = 1; series.ScrollingStabilizing = true; series.AllowUserInteraction = false; v.SampleDataSeries.Add(series); } } } private void UpdateChartData() { double[][] multiChannelData = new double[smList.Count * 3][]; try { for (int channelIndex = 0; channelIndex < smList.Count; channelIndex++) { multiChannelData[channelIndex * 3] = smList.ElementAt(channelIndex).dz.ToArray(); multiChannelData[channelIndex * 3 + 1] = smList.ElementAt(channelIndex).dn.ToArray(); multiChannelData[channelIndex * 3 + 2] = smList.ElementAt(channelIndex).de.ToArray(); } // Invoke FeedNewDataToChart. _dispatcher.Invoke(() => { FeedNewDataToChar(multiChannelData); }); } catch (Exception ex) { throw ex; } } private void ApplicationClosingDispose(object sender, CancelEventArgs e) { if (LChartALL != null) { LChartALL.Dispose(); LChartALL = null; } } private void DisposeAllAndClear(List list) where T : IDisposable { if (list == null) { return; } while (list.Count > 0) { int lastInd = list.Count - 1; T item = list[lastInd]; // take item ref from list. list.RemoveAt(lastInd); // remove item first if (item != null) { (item as IDisposable).Dispose(); // then dispose it. } } } public void Dispose() { gridChart.Children.Clear(); if (LChartALL != null) { LChartALL.Dispose(); LChartALL = null; } } private void FeedNewDataToChar(double[][] data) { LChartALL.BeginUpdate(); _wavesModel.CreateAxisYEventTime(CurrentEventTime, LChartALL.ViewXY, smList.ToList()); for (int channelIndex = 0; channelIndex < _channelCount; channelIndex++) { LChartALL.ViewXY.SampleDataSeries[channelIndex].AddSamples(data[channelIndex], true); } LChartALL.EndUpdate(); } } }