From f3fdfbfa1fd67e0cc84c74b085730c4e2636372c Mon Sep 17 00:00:00 2001 From: Tongg Date: Mon, 7 Apr 2025 16:13:59 +0800 Subject: [PATCH] feat: Image Broadcast as you go --- Model/Extension/CommonExtension.cs | 16 ++- ViewModel/Grading/DiamondSelectVM.cs | 6 +- ViewModel/Grading/GradingLoadingVM.cs | 116 ++++++++++++++---- Views/UserControl/Viewport3D.xaml | 2 +- Views/UserControl/Viewport3D.xaml.cs | 8 +- .../ViewportData/Helper/CommonHelper.cs | 15 +-- .../ViewportData/Helper/ViewportHelperPro.cs | 29 ++--- .../UserControl/ViewportData/ViewportData.cs | 58 +++++---- 8 files changed, 170 insertions(+), 80 deletions(-) diff --git a/Model/Extension/CommonExtension.cs b/Model/Extension/CommonExtension.cs index d892ed9..6b354b1 100644 --- a/Model/Extension/CommonExtension.cs +++ b/Model/Extension/CommonExtension.cs @@ -42,9 +42,19 @@ public static class CommonExtension return toStringMethod?.DeclaringType != typeof(object); }); - return hasCustomToString - ? obj.ToString() // 使用自定义的ToString - : JsonConvert.SerializeObject(obj); // 未重写时序列化为JSON + try + { + string result = hasCustomToString + ? obj.ToString() // 使用自定义的ToString + : JsonConvert.SerializeObject(obj); + return result; + } + catch (Exception e) + { + return obj.ToString(); + } + + } diff --git a/ViewModel/Grading/DiamondSelectVM.cs b/ViewModel/Grading/DiamondSelectVM.cs index a823e73..31d3799 100644 --- a/ViewModel/Grading/DiamondSelectVM.cs +++ b/ViewModel/Grading/DiamondSelectVM.cs @@ -141,11 +141,7 @@ public class DiamondSelectVM : BaseViewModel }; listBtn.ForEach(e => tempButtons2.Add(e)); - // tempButtons2.Add(button1); - // tempButtons2.Add(button2); - // tempButtons2.Add(button3); - // tempButtons2.Add(button4); - // tempButtons2.Add(button5); + } diff --git a/ViewModel/Grading/GradingLoadingVM.cs b/ViewModel/Grading/GradingLoadingVM.cs index bed5641..2f443c3 100644 --- a/ViewModel/Grading/GradingLoadingVM.cs +++ b/ViewModel/Grading/GradingLoadingVM.cs @@ -1,5 +1,6 @@ using System.Configuration; using System.Data; +using System.Diagnostics; using System.IO; using System.Text; using System.Windows; @@ -192,9 +193,9 @@ public class GradingLoadingVM : BaseViewModel,IDisposable // return -1; // } - var processImage = SOCClientService.Service.ProcessImageCollectionAsync(); + Task processImage = SOCClientService.Service.ProcessImageCollectionAsync(); //通知页面可以播放图片 - + LoadDefaultImages(); await processImage; if (!("ok".Equals(processImage.Result.Status) || "S000".Equals(processImage.Result.Status))) @@ -204,7 +205,7 @@ public class GradingLoadingVM : BaseViewModel,IDisposable MultilingualHelper.getString(StatusCodes.GetConstantNameByValue(processImage.Result.Status))); return -1; } - LoadImages(processImage.Result.Images); + // LoadImages(processImage.Result.Images); } @@ -228,12 +229,12 @@ public class GradingLoadingVM : BaseViewModel,IDisposable { return -1; } - + StartPlayback(); } ImageIsEnable = true; - StartPlayback(); + // StartPlayback(); if (_isCancel == true) { SOCClientService.Service.OpenPump(false); @@ -370,6 +371,12 @@ public class GradingLoadingVM : BaseViewModel,IDisposable parameter.PavType = _diamnondType.Split(" ")[2]; parameter.ErrorMsg = _diamnondType; + //实验室模式关闭气泵 + if (Common.RunMode == 0) + { + SOCClientService.Service.OpenPump(false); + } + try { Logger.Info($"算法结果Json单独保存至log/result"); @@ -420,21 +427,7 @@ public class GradingLoadingVM : BaseViewModel,IDisposable } } } - [Log] - private async Task CompleteProgressSlowlyAsync() - { - // 缓慢完成剩余3%(总耗时保持原速度的3倍) - const int remainingSteps = 3; - int stepTime = 500; // 自定义慢速步长 - - int current = (int)Progress; - for (int i = 1; i <= remainingSteps; i++) - { - if (_progressCts.IsCancellationRequested) break; - UpdateProgress(current + i); - await Task.Delay(stepTime); - } - } + [Log] private async Task CompleteProgressQuicklyAsync() { @@ -557,11 +550,20 @@ public class GradingLoadingVM : BaseViewModel,IDisposable } #region 图片播放处理 [Log] - public void LoadImages(string folderPath) + public void LoadDefaultImages() { - ImagePaths = Directory.GetFiles(folderPath, "*.bmp"); + List imagePaths = new List(); + string? savePath = ConfigurationManager.AppSettings["ImageFileBasePath"]; + for (int i = 0; i < 100; i++) + { + imagePaths.Add(Path.Combine(savePath, $"image_{i}.bmp")); + } + + ImagePaths = imagePaths.ToArray(); CurrentIndex = 0; CurrentStatus = PlayStatus.Stopped; + + MonitorAndPlayImagesAsync(savePath); } [Log] public void LoadImages(List folderPath) @@ -570,6 +572,76 @@ public class GradingLoadingVM : BaseViewModel,IDisposable CurrentIndex = 0; CurrentStatus = PlayStatus.Stopped; } + + [Log] + private async Task MonitorAndPlayImagesAsync(string folderPath) + { + var sw = new Stopwatch(); + for (int i = 0; i < 100; i++) + { + sw.Restart(); + + // 等待文件就绪 + var filePath = Path.Combine(folderPath, $"image_{i}.bmp"); + while (!await IsFileReady(filePath)) + { + await Task.Delay(50); // 每50ms检测一次文件状态 + } + + // 加载图片到内存 + var image = await LoadImageSafely(filePath); + + // 更新UI显示 + await Application.Current.Dispatcher.InvokeAsync(() => + { + CurrentImage = image; + OnPropertyChanged(nameof(CurrentImage)); + }); + + // 强制最小显示间隔 + var remainTime = Math.Max(100 - (int)sw.ElapsedMilliseconds, 0); + await Task.Delay(remainTime); + } + } + [Log] + private async Task IsFileReady(string path) + { + try + { + // 双重验证机制 + if (!File.Exists(path)) return false; + + // 尝试读取文件头验证完整性 + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + byte[] header = new byte[2]; + await fs.ReadAsync(header, 0, 2); + return header[0] == 0x42 && header[1] == 0x4D; // BMP文件头标识 + } + } + catch + { + return false; + } + } + [Log] + private async Task LoadImageSafely(string path) + { + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + var bitmap = new BitmapImage(); + await Application.Current.Dispatcher.InvokeAsync(() => + { + bitmap.BeginInit(); + bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.StreamSource = fs; + bitmap.EndInit(); + bitmap.Freeze(); // 跨线程安全 + }); + return bitmap; + } + } + [Log] private async Task HandlePlayControl() { diff --git a/Views/UserControl/Viewport3D.xaml b/Views/UserControl/Viewport3D.xaml index 0e2845f..d3f5549 100644 --- a/Views/UserControl/Viewport3D.xaml +++ b/Views/UserControl/Viewport3D.xaml @@ -55,7 +55,7 @@ - + diff --git a/Views/UserControl/Viewport3D.xaml.cs b/Views/UserControl/Viewport3D.xaml.cs index f3f2aa9..ffc20a1 100644 --- a/Views/UserControl/Viewport3D.xaml.cs +++ b/Views/UserControl/Viewport3D.xaml.cs @@ -85,6 +85,12 @@ public partial class Viewport3D // Viewport3Dx.ShowFrameRate = !Viewport3Dx.ShowFrameRate; // Viewport3Dx.ShowTriangleCountInfo = !Viewport3Dx.ShowTriangleCountInfo; + if (Common.RunMode == 0) + { + ContextMenu.Items.Remove(ViewportCutXuanZ); + ContextMenu.Items.Remove(ViewportCutXuanZSeparator); + } + //工厂模式屏蔽一些东西 string step = ViewportManager.DiamondType.Split(" ").Last(); if (Common.RunMode == 1 && step.StartsWith("S")) @@ -140,8 +146,6 @@ public partial class Viewport3D ViewportManager.ShowMainModelLines(true); ViewportManager.ShowMainModel3D(true); ViewportManager.ShowMainModel3DByType(true); - - } diff --git a/Views/UserControl/ViewportData/Helper/CommonHelper.cs b/Views/UserControl/ViewportData/Helper/CommonHelper.cs index 0df816e..b588bb9 100644 --- a/Views/UserControl/ViewportData/Helper/CommonHelper.cs +++ b/Views/UserControl/ViewportData/Helper/CommonHelper.cs @@ -7,6 +7,7 @@ using SharpDX; using SparkClient.Model.Attributes; using SparkClient.Views.UserControl.ViewportData.Entity; using SparkClient.Views.UserControl.ViewportData.Enum; +using SparkDotNetCore.DiamondScanner.Entity.Child; namespace SparkClient.Views.UserControl.ViewportData.Helper; @@ -27,11 +28,11 @@ public class CommonHelper public static Viewport3DTriangleEntity CreateByJsonStr(string json) { // 解析 JSON 数据 - var jsonObject = JsonConvert.DeserializeObject(json); - if (jsonObject == null) throw new ArgumentException("Json object is null"); + var facet = JsonConvert.DeserializeObject(json); + if (facet == null) throw new ArgumentException("Json object is null"); // 提取坐标 - var coords = jsonObject.coords.ToObject(); - if (coords.Length < 3) + var coords = facet.coords; + if (coords.Count < 3) { throw new ArgumentException("The input JSON does not have enough points to form a triangle."); } @@ -45,9 +46,9 @@ public class CommonHelper // var point3 = new Vector3((float)coords[2].x, (float)coords[2].y, (float)coords[2].z); // 提取 PlaneCode 和 PlaneType - string planeCode = jsonObject.facet_id ?? (string)jsonObject.facet_id; - PlaneType planeType = (PlaneType)(int)jsonObject.facet_type; - double theta = jsonObject.theta ?? (double)jsonObject.theta; + string planeCode = facet.facet_id; + PlaneType planeType = (PlaneType)int.Parse(facet.facet_type); + double theta = facet.theta; // 生成 TriangleCode var triangleCode = GenerateTriangleCode(point1, point2, point3); diff --git a/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs b/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs index 9d4c2d8..5d97594 100644 --- a/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs +++ b/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs @@ -14,13 +14,9 @@ using SparkClient.Views.UserControl.ViewportData.Enum; using SparkClient.Views.UserControl.ViewportData.Entity; using Color = SharpDX.Color; using GeometryModel3D = HelixToolkit.Wpf.SharpDX.GeometryModel3D; -using MeshGeometry3D = HelixToolkit.Wpf.SharpDX.MeshGeometry3D; using Point = System.Windows.Point; -using PerspectiveCamera = HelixToolkit.Wpf.SharpDX.PerspectiveCamera; -using System.Windows.Controls; using HelixToolkit.Wpf; using MeshBuilder = HelixToolkit.Wpf.SharpDX.MeshBuilder; -using OrthographicCamera = HelixToolkit.Wpf.SharpDX.OrthographicCamera; using System.Windows.Input; using SparkClient.Model.Attributes; using SparkClient.Model.Extension; @@ -51,6 +47,7 @@ public class ViewportHelperPro /// /// /// + /// [Log] public static MeshGeometryModel3D GenerateModelByEntity(Viewport3DX viewport, List entities, Color4? color = null) { @@ -112,7 +109,6 @@ public class ViewportHelperPro /// 通过三角形实体集合生成面模型(只生成不添加) /// /// - /// /// [Log] public static List GenerateModelByEntityGroupByType(List entities) @@ -185,7 +181,7 @@ public class ViewportHelperPro } [Log] - public static async Task ExportModelsToVideo(Viewport3DX viewport, string filePath) + public static async Task ExportModelsToVideo(Viewport3DX? viewport, string filePath) { if (viewport == null) viewport = ViewportManager.GetViewport3D(); @@ -203,7 +199,7 @@ public class ViewportHelperPro /// /// [Log] - public static void ExportModelsToStl(Viewport3DX viewport, string filePath) + public static void ExportModelsToStl(Viewport3DX? viewport, string filePath) { if (viewport == null) viewport = ViewportManager.GetViewport3D(); @@ -214,7 +210,7 @@ public class ViewportHelperPro foreach (var model in viewport.Items.OfType()) { - if (model.Geometry is HelixToolkit.Wpf.SharpDX.Geometry3D geometry) + if (model.Geometry != null && model.Geometry is HelixToolkit.Wpf.SharpDX.Geometry3D geometry) { var positions = geometry.Positions; var indices = geometry.Indices; @@ -252,7 +248,6 @@ public class ViewportHelperPro /// /// 导出模型 /// - /// /// [Log] public static async Task ExportModelsToStlASync(string filePath) @@ -379,7 +374,7 @@ public class ViewportHelperPro { culetLineZ, culetLineX }; result.Add(DisplayLineModel3D(centerLines, Color.Red, 0.8f)); - result.Add(DisplayLineModel3D(tableLines, Color.Green, 1f)); + result.Add(DisplayLineModel3D(tableLines, Color.Green)); result.Add(DisplayLineModel3D(culetLines, Color.Blue, 0.8f)); return result; } @@ -389,6 +384,8 @@ public class ViewportHelperPro /// /// /// + /// + /// [Log] public static List GentrateLineByEntity(Viewport3DX viewport, List entities, Color4? color = null, double thickness = 1.0) { @@ -599,11 +596,11 @@ public class ViewportHelperPro public static List GenerateLineTextModels(List entities, string valKey = "") { var result = new List(); - string steps = ViewportManager.DiamondType.Split(" ").Last(); + // string steps = ViewportManager.DiamondType.Split(" ").Last(); if (Common.RunMode == 0) { Logger.Info("【面文本生成】开始生成面相关文本信息"); - var selFacet = entities; + // var selFacet = entities; var selFacetType = entities.First().PlaneType; @@ -729,7 +726,7 @@ public class ViewportHelperPro var facetIndex = int.Parse(dic.Key.Split("_")[1]) - 1; if ("GIRDLE_VALLEY".Equals(gridleResult.Key)) { - var showLine =GetLeftOrRightLineSegment(facetPoints, facetIndex >= 25 && facetIndex <= 57 ? true : false);; + var showLine =GetLeftOrRightLineSegment(facetPoints, facetIndex >= 25 && facetIndex <= 57 ); if (showLine == null) continue; result.Add(DisplayLineModel3D(new List>() { showLine }, new Color4(1f, 0, 0, 1f), 2f)); } @@ -752,7 +749,7 @@ public class ViewportHelperPro return result; } - var valueFloat = ValueFormat(paramValue.ToString(), gridleResult.Key, false); + var valueFloat = ValueFormat(paramValue.ToString(), gridleResult.Key); result.Add(DisplayText3D($"{valueFloat}", facetTextPoint)); } } @@ -796,7 +793,7 @@ public class ViewportHelperPro //高亮的线 // var showLine = GetLeftParallelLineSegment(facetPoints); var facetIndex = int.Parse(dic.Key.Split("_")[1]) - 1; - var showLine =GetLeftOrRightLineSegment(facetPoints, facetIndex >= 25 && facetIndex <= 57 ? true : false);; + var showLine =GetLeftOrRightLineSegment(facetPoints, facetIndex >= 25 && facetIndex <= 57);; if (showLine == null) continue; //文字显示位置 @@ -2311,7 +2308,7 @@ public class ViewportHelperPro return resultSegment; // 返回符合条件的线段 } [Log] - private static Tuple GetLeftOrRightLineSegment(List facetPoints, + private static Tuple? GetLeftOrRightLineSegment(List facetPoints, bool isLeft = true) { Tuple resultSegment = null; diff --git a/Views/UserControl/ViewportData/ViewportData.cs b/Views/UserControl/ViewportData/ViewportData.cs index 69f6ccf..f2e9944 100644 --- a/Views/UserControl/ViewportData/ViewportData.cs +++ b/Views/UserControl/ViewportData/ViewportData.cs @@ -1,11 +1,14 @@ using System.Text.Json.Nodes; +using Newtonsoft.Json; using SharpDX; using SparkClient.Model.Attributes; +using SparkClient.Model.Entity.ApiEntity; using SparkClient.Model.Extension; using SparkClient.Model.Helper; using SparkClient.Views.UserControl.ViewportData.Entity; using SparkClient.Views.UserControl.ViewportData.Enum; using SparkClient.Views.UserControl.ViewportData.Helper; +using SparkDotNetCore.DiamondScanner.Entity; namespace SparkClient.Views.UserControl.ViewportData; @@ -53,27 +56,31 @@ public class ViewportData [Log] public void LoadData() { - JsonNode? json = null; + var settings = new JsonSerializerSettings + { + ContractResolver = new DefaultValueContractResolver(), + NullValueHandling = NullValueHandling.Ignore + }; + DiaResult? diamondData = null; try { - json = JsonNode.Parse(DiamondData); + diamondData = JsonConvert.DeserializeObject(DiamondData.ToSafeString(),settings); } catch { throw new Exception("DiamondData is invalid"); } - if(json == null) throw new Exception("DiamondData is invalid"); + if(diamondData == null) throw new Exception("DiamondData is invalid"); try { List facets = new List(); - if (json.AsObject()["facets"] != null) + if (diamondData.Facets != null) { - JsonArray jsonArray = json.AsObject()["facets"].AsArray(); - foreach (var item in jsonArray) + foreach (var item in diamondData.Facets) { - var value = CommonHelper.CreateByJsonStr(item.ToString()); + var value = CommonHelper.CreateByJsonStr(JsonConvert.SerializeObject(item, settings)); facets.Add(value); } } @@ -82,24 +89,27 @@ public class ViewportData throw new Exception("facets is invalid"); } - if (json.AsObject()["positive_direction"] != null) - { - JsonObject positive = json.AsObject()["positive_direction"].AsObject(); - ViewportManager.PositiveDirection.X = float.Parse(positive["x"]?.ToString() ?? "1.0"); - ViewportManager.PositiveDirection.Y = float.Parse(positive["z"]?.ToString() ?? "0"); - ViewportManager.PositiveDirection.Z = float.Parse(positive["y"]?.ToString() ?? "0"); - } - else - { - ViewportManager.PositiveDirection.X = 1.0f; - ViewportManager.PositiveDirection.Y = 0f; - ViewportManager.PositiveDirection.Z = 0; - } + // if (json.AsObject()["positive_direction"] != null) + // { + // JsonObject positive = json.AsObject()["positive_direction"].AsObject(); + // ViewportManager.PositiveDirection.X = float.Parse(positive["x"]?.ToString() ?? "1.0"); + // ViewportManager.PositiveDirection.Y = float.Parse(positive["z"]?.ToString() ?? "0"); + // ViewportManager.PositiveDirection.Z = float.Parse(positive["y"]?.ToString() ?? "0"); + // } + // else + // { + // ViewportManager.PositiveDirection.X = 1.0f; + // ViewportManager.PositiveDirection.Y = 0f; + // ViewportManager.PositiveDirection.Z = 0; + // } + ViewportManager.PositiveDirection.X = 1.0f; + ViewportManager.PositiveDirection.Y = 0f; + ViewportManager.PositiveDirection.Z = 0; ViewportManager.DiamondCode = DiamondCode; - ViewportManager.DiamondType = json.AsObject()["error_msg"].ToSafeString(); - var measurements = json.AsObject()["measurements"]; - ViewportManager.DiamondData = measurements==null?new JsonObject():measurements.AsObject(); + ViewportManager.DiamondType = diamondData.ErrorMsg.ToSafeString(); + + ViewportManager.DiamondData = JsonObject.Parse(JsonConvert.SerializeObject(diamondData.Measurements)).AsObject(); var midZ = facets.SelectMany(e => new[] { e.Point1.X, e.Point2.X, e.Point3.X }).OrderBy(z => Math.Abs(z)) .First(); List facetsFinal = new List(); @@ -150,7 +160,7 @@ public class ViewportData facetsFinal.Add(item); } - if (json["status"].ToString().Equals("P021")) + if (diamondData.Status.Equals("P021")) { ViewportManager.isUglyDiamond = true; }