diff --git a/Txgy.EWS.Client.PageModule/ViewModels/ReportViewModel.cs b/Txgy.EWS.Client.PageModule/ViewModels/ReportViewModel.cs index 63f8ea5..28e3ffc 100644 --- a/Txgy.EWS.Client.PageModule/ViewModels/ReportViewModel.cs +++ b/Txgy.EWS.Client.PageModule/ViewModels/ReportViewModel.cs @@ -80,7 +80,18 @@ namespace Txgy.EWS.Client.PageModule.ViewModels public int CompletedCount { get; set; } public int TotalCount { get; set; } public string Message { get; set; } + public double? Percent { get; set; } + public bool IsIndeterminate { get; set; } + public bool ShowCount { get; set; } } + + private const double SearchProgressQueryComplete = 5; + private const double SearchProgressComputeComplete = 80; + private const double SearchProgressListComplete = 84; + private const double SearchProgressEnergyComplete = 87; + private const double SearchProgressDayFreqComplete = 90; + private const double SearchProgressPlanComplete = 95; + private const double SearchProgressComplete = 100; /// /// 查询模式:0:自定义查询;1:日报;2:周报;3:月报 /// @@ -444,7 +455,7 @@ namespace Txgy.EWS.Client.PageModule.ViewModels ResetSearchProgress("正在查询事件数据..."); var progress = new Progress(UpdateSearchProgress); var results = await SearchEventsAsync(st, et, progress); - ApplySearchResults(rView, results, st, createDayFreq); + await ApplySearchResultsAsync(rView, results, st, createDayFreq, progress); } catch (Exception ex) { @@ -456,33 +467,78 @@ namespace Txgy.EWS.Client.PageModule.ViewModels } } - private void ApplySearchResults(ReportView rView, List results, DateTime st, bool createDayFreq) + private async Task ApplySearchResultsAsync(ReportView rView, List results, DateTime st, bool createDayFreq, IProgress progress) { if (results == null) { return; } - SelectResult = new ObservableCollection(results); - SearchCount = results.Count; + await RefreshResultListAsync(results, progress); + progress.Report(CreateStageProgress("正在统计能量", SearchProgressListComplete)); + await YieldToUiAsync(); UpdateEnergyStats(results); if (createDayFreq) { + progress.Report(CreateStageProgress("正在生成频度图", SearchProgressEnergyComplete)); + await YieldToUiAsync(); FreqChart = CreateDayFreqImage(results, st, st.ToString("D", culture)); } + progress.Report(CreateStageProgress("正在筛选中等能量事件", SearchProgressDayFreqComplete)); + await YieldToUiAsync(); var mes = results.Where(rs => rs.Energy >= MiddleEnergy).ToList(); MiddleEnergyEvents = mes; MiddleEventCount = mes.Count(); if (mes.Count > 0 && rView != null) { + progress.Report(CreateStageProgress("正在绘制平面图", SearchProgressDayFreqComplete)); + await YieldToUiAsync(); ReportPlanImage rpi = new ReportPlanImage(); rpi.Draw(mes, rView.canvasPlan.ActualWidth, rView.canvasPlan.ActualHeight); rView.canvasPlan.Children.Clear(); rView.canvasPlan.Children.Add(rpi.host); + progress.Report(CreateStageProgress("正在生成三维图", SearchProgressPlanComplete)); + await YieldToUiAsync(); CreateStereoChart(mes); } + progress.Report(CreateStageProgress("查询完成", SearchProgressComplete)); + await YieldToUiAsync(); + } + + private async Task RefreshResultListAsync(List results, IProgress progress) + { + SelectResult = new ObservableCollection(); + SearchCount = results.Count; + + if (results.Count == 0) + { + progress.Report(CreateStageProgress("正在刷新事件列表", SearchProgressListComplete)); + await YieldToUiAsync(); + return; + } + + const int batchSize = 50; + for (int i = 0; i < results.Count; i++) + { + SelectResult.Add(results[i]); + if ((i + 1) % batchSize == 0 || i == results.Count - 1) + { + double percent = SearchProgressComputeComplete + + ((i + 1) / (double)results.Count) * (SearchProgressListComplete - SearchProgressComputeComplete); + progress.Report(new SearchProgressInfo + { + CompletedCount = i + 1, + TotalCount = results.Count, + Message = "正在刷新事件列表", + Percent = percent, + IsIndeterminate = false, + ShowCount = true + }); + await YieldToUiAsync(); + } + } } private void ResetSearchProgress(string message) @@ -500,9 +556,23 @@ namespace Txgy.EWS.Client.PageModule.ViewModels return; } + if (progress.Percent.HasValue) + { + double explicitPercent = Math.Max(0, Math.Min(100, progress.Percent.Value)); + SearchProgressIndeterminate = progress.IsIndeterminate; + SearchProgressValue = explicitPercent; + SearchProgressPercentText = progress.IsIndeterminate ? "" : explicitPercent.ToString("F0") + "%"; + SearchProgressText = BuildSearchProgressText(progress); + if (progress.TotalCount > 0) + { + SearchCount = progress.TotalCount; + } + return; + } + if (progress.TotalCount <= 0) { - SearchProgressIndeterminate = progress.Message != "未查询到事件"; + SearchProgressIndeterminate = progress.IsIndeterminate || progress.Message != "未查询到事件"; SearchProgressValue = 0; SearchProgressPercentText = progress.Message == "未查询到事件" ? "0%" : ""; SearchProgressText = progress.Message; @@ -518,7 +588,65 @@ namespace Txgy.EWS.Client.PageModule.ViewModels SearchProgressIndeterminate = false; SearchProgressValue = percent; SearchProgressPercentText = percent.ToString("F0") + "%"; - SearchProgressText = progress.Message + " " + progress.CompletedCount + "/" + progress.TotalCount; + SearchProgressText = BuildSearchProgressText(progress); + } + + private string BuildSearchProgressText(SearchProgressInfo progress) + { + if (progress.ShowCount && progress.TotalCount > 0) + { + return progress.Message + " " + progress.CompletedCount + "/" + progress.TotalCount; + } + return progress.Message; + } + + private SearchProgressInfo CreateStageProgress(string message, double percent, bool isIndeterminate = false) + { + return new SearchProgressInfo + { + CompletedCount = 0, + TotalCount = 0, + Message = message, + Percent = percent, + IsIndeterminate = isIndeterminate, + ShowCount = false + }; + } + + private SearchProgressInfo CreateEventProgress(int completedCount, int totalCount, int stageIndex, int stageCount, string message) + { + if (totalCount <= 0) + { + return CreateStageProgress(message, SearchProgressQueryComplete); + } + + int safeStageIndex = Math.Max(0, Math.Min(stageIndex, stageCount)); + double eventProgress = (completedCount + safeStageIndex / (double)stageCount) / totalCount; + double percent = SearchProgressQueryComplete + eventProgress * (SearchProgressComputeComplete - SearchProgressQueryComplete); + int displayCount = Math.Min(completedCount + 1, totalCount); + + return new SearchProgressInfo + { + CompletedCount = displayCount, + TotalCount = totalCount, + Message = message, + Percent = percent, + IsIndeterminate = false, + ShowCount = true + }; + } + + private void ReportSearchProgress(IProgress progress, SearchProgressInfo progressInfo) + { + if (progress != null) + { + progress.Report(progressInfo); + } + } + + private static async Task YieldToUiAsync() + { + await Task.Delay(1); } /// @@ -707,7 +835,7 @@ namespace Txgy.EWS.Client.PageModule.ViewModels } private Task> SearchEventsAsync(DateTime searchStartTime, DateTime searchEndTime, IProgress progress) { - return Task.Run(() => SearchEventsCore(searchStartTime, searchEndTime, progress)); + return SearchEventsCoreAsync(searchStartTime, searchEndTime, progress); } public List SearchEvents(DateTime searchStartTime, DateTime searchEndTime) @@ -719,6 +847,11 @@ namespace Txgy.EWS.Client.PageModule.ViewModels } private List SearchEventsCore(DateTime searchStartTime, DateTime searchEndTime, IProgress progress) + { + return SearchEventsCoreAsync(searchStartTime, searchEndTime, progress).GetAwaiter().GetResult(); + } + + private async Task> SearchEventsCoreAsync(DateTime searchStartTime, DateTime searchEndTime, IProgress progress) { List results = new List(); string findStr = "select * from " + GlobalConfig.UseResultTable; @@ -761,30 +894,21 @@ namespace Txgy.EWS.Client.PageModule.ViewModels } if (progress != null) { - progress.Report(new SearchProgressInfo - { - CompletedCount = 0, - TotalCount = 0, - Message = "正在查询事件数据..." - }); + progress.Report(CreateStageProgress("正在查询事件数据...", 0, true)); } - var list = fsqlTencent.Select() - .WithSql(findStr).ToList(); + var list = await Task.Run(() => fsqlTencent.Select() + .WithSql(findStr).ToList()).ConfigureAwait(false); int totalCount = list == null ? 0 : list.Count; - if (progress != null) - { - progress.Report(new SearchProgressInfo - { - CompletedCount = 0, - TotalCount = totalCount, - Message = totalCount == 0 ? "未查询到事件" : "正在计算震源机制" - }); - } + ReportSearchProgress(progress, totalCount == 0 + ? CreateStageProgress("未查询到事件", 0) + : CreateEventProgress(0, totalCount, 0, 4, "正在准备事件")); if (list != null) { int completedCount = 0; + const int eventStageCount = 4; foreach (var item in list) { + ReportSearchProgress(progress, CreateEventProgress(completedCount, totalCount, 0, eventStageCount, "正在准备事件")); GridItemEventResult se = new GridItemEventResult(item, true); string eventTimeStr = se.EventTime; string datePath = eventTimeStr.Substring(0, 4) + eventTimeStr.Substring(5, 2) + eventTimeStr.Substring(8, 2); @@ -793,39 +917,49 @@ namespace Txgy.EWS.Client.PageModule.ViewModels + eventTimeStr.Substring(8, 2) + eventTimeStr.Substring(10, 3) + eventTimeStr.Substring(14, 2) + eventTimeStr.Substring(17, 2) + ".01" + GlobalConfig.DataTypeString; string jsonStr = ".json"; + string jsonFilePath = dataFilePath + dataFileName + jsonStr; MmEvent curMmEvent = new MmEvent(); curMmEvent.EventTimeStr = eventTimeStr; curMmEvent.X = se.X; curMmEvent.Y = se.Y; curMmEvent.RMS = se.RMS; curMmEvent.DominantFreq = 15; + bool canComputeWaveform = false; //查询事件Json文件是否已下载 - if (File.Exists(dataFilePath + dataFileName + jsonStr)) + if (File.Exists(jsonFilePath)) { - FileInfo fileInfo = new FileInfo(dataFilePath + dataFileName + jsonStr); + FileInfo fileInfo = new FileInfo(jsonFilePath); if (fileInfo.Length > 1024) { - ComputeFM(curMmEvent); - //目前提取的为半周期 - curMmEvent.DominantFreq = GlobalData.GetDominFreq(eventTimeStr); + canComputeWaveform = true; } } else { #region 同步方式 - int res = new DownloadJsonFile().Download(eventTimeStr, dataFilePath, dataFileName + jsonStr, GlobalConfig.UseWaveDataTable); + ReportSearchProgress(progress, CreateEventProgress(completedCount, totalCount, 1, eventStageCount, "正在下载波形JSON")); + int res = await DownloadJsonFile.DownloadAsync(eventTimeStr, dataFilePath, dataFileName + jsonStr, GlobalConfig.UseWaveDataTable).ConfigureAwait(false); if (res > -1) { - FileInfo fileInfo2 = new FileInfo(dataFilePath + dataFileName + jsonStr); + FileInfo fileInfo2 = new FileInfo(jsonFilePath); if (fileInfo2.Length > 2000) { - ComputeFM(curMmEvent); - //目前提取的为半周期 - curMmEvent.DominantFreq = GlobalData.GetDominFreq(eventTimeStr); + canComputeWaveform = true; } } #endregion } + + if (canComputeWaveform) + { + ReportSearchProgress(progress, CreateEventProgress(completedCount, totalCount, 1, eventStageCount, "正在读取波形JSON")); + JObject eventJson = ReadEventJsonRoot(jsonFilePath); + ReportSearchProgress(progress, CreateEventProgress(completedCount, totalCount, 2, eventStageCount, "正在计算震源机制")); + ComputeFM(curMmEvent, eventJson, jsonFilePath); + ReportSearchProgress(progress, CreateEventProgress(completedCount, totalCount, 3, eventStageCount, "正在计算主频")); + //目前提取的为半周期 + curMmEvent.DominantFreq = GetDominFreq(eventJson); + } Random dominRnd = new Random((int)DateTime.Parse(curMmEvent.EventTimeStr).Ticks); int dominFreq = (int)curMmEvent.DominantFreq; @@ -838,16 +972,8 @@ namespace Txgy.EWS.Client.PageModule.ViewModels se.Direction = curMmEvent.Direction; se.SetEnergy(); results.Add(se); + ReportSearchProgress(progress, CreateEventProgress(completedCount, totalCount, eventStageCount, eventStageCount, "正在整理事件结果")); completedCount++; - if (progress != null) - { - progress.Report(new SearchProgressInfo - { - CompletedCount = completedCount, - TotalCount = totalCount, - Message = "正在计算震源机制" - }); - } } } return results; @@ -867,6 +993,41 @@ namespace Txgy.EWS.Client.PageModule.ViewModels AverageEnergy = Math.Round(results.Average(rs => rs.Energy), 2); MaxEnergy = Math.Round(results.Max(rs => rs.Energy), 2); } + + private JObject ReadEventJsonRoot(string jsonFilePath) + { + using (StreamReader sr = System.IO.File.OpenText(jsonFilePath)) + { + JsonTextReader reader = new JsonTextReader(sr); + JArray jArray = (JArray)JToken.ReadFrom(reader); + return (JObject)jArray[0]; + } + } + + private int GetDominFreq(JObject eventJson) + { + int dominantFreq = 0; + List dominantFreqList = new List(); + JArray phaseArr = JArray.FromObject(eventJson["phases"]); + for (int i = 0; i < phaseArr.Count; i++) + { + if (phaseArr[i]["zcr"] != null) + { + dominantFreqList.Add(double.Parse(phaseArr[i]["zcr"].ToString())); + } + } + + if (dominantFreqList.Count > 3) + { + double min = dominantFreqList.Min(); + double max = dominantFreqList.Max(); + dominantFreqList.Remove(min); + dominantFreqList.Remove(max); + dominantFreq = (int)(dominantFreqList.Sum() / dominantFreqList.Count); + } + + return dominantFreq; + } public void ExportEventListReport(ReportView rView) { @@ -1350,6 +1511,30 @@ namespace Txgy.EWS.Client.PageModule.ViewModels mmEvent.FocalType = cr.FocalType; mmEvent.Direction = cr.Direction; } + + public void ComputeFM(MmEvent mmEvent, JObject eventJson, string jsonFilePath) + { + mmEvent.JsonFile = jsonFilePath; + mmEvent.SetEnergy(); + mmEvent.Phases = new Dictionary(); + JArray phaseArr = JArray.FromObject(eventJson["phases"]); + for (int i = 0; i < phaseArr.Count; i++) + { + if (phaseArr[i]["first_motion_direct"] != null) + { + mmEvent.Phases.Add(phaseArr[i]["id"].ToString().Substring(3, 3), + int.Parse(phaseArr[i]["first_motion_direct"].ToString())); + } + } + + FMMap fmMap = CreateFM(mmEvent, GlobalConfig.ProjectConfig.WorkArea.EMin, GlobalConfig.ProjectConfig.WorkArea.NMin); + ComputationResult cr = GlobalConfig.fmCore.ComputeResult(fmMap); + if (cr == null) + return; + mmEvent.FocalType = cr.FocalType; + mmEvent.Direction = cr.Direction; + } + public FMMap CreateFM(MmEvent mmEvent, double BaseX, double BaseY) { FMMap fmMap = new FMMap();