From 3b4b794dd05c3023c180abbc516850c934faaa89 Mon Sep 17 00:00:00 2001 From: "zhengxuan.zhang" Date: Tue, 21 Apr 2026 01:49:09 +0800 Subject: [PATCH] =?UTF-8?q?#=E5=88=9D=E6=AD=A5=E7=9A=84cnc=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=AE=9E=E7=8E=B0=E6=8F=92?= =?UTF-8?q?=E5=85=A5=E5=8F=82=E8=80=83=E7=82=B9=E7=9A=84=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XplorePlane/Models/CncModels.cs | 5 ++- XplorePlane/Services/Cnc/CncProgramService.cs | 32 +++++++++++++- .../ViewModels/Cnc/CncEditorViewModel.cs | 12 +++--- XplorePlane/ViewModels/Main/MainViewModel.cs | 42 ++++++++++++++++++- XplorePlane/Views/Cnc/CncPageView.xaml | 3 +- XplorePlane/Views/Main/MainWindow.xaml | 15 +++++-- 6 files changed, 94 insertions(+), 15 deletions(-) diff --git a/XplorePlane/Models/CncModels.cs b/XplorePlane/Models/CncModels.cs index 5672544..56c1014 100644 --- a/XplorePlane/Models/CncModels.cs +++ b/XplorePlane/Models/CncModels.cs @@ -46,7 +46,8 @@ namespace XplorePlane.Models /// 参考点节点 | Reference point node public record ReferencePointNode( Guid Id, int Index, string Name, - double XM, double YM, double ZT, double ZD, double TiltD, double Dist + double XM, double YM, double ZT, double ZD, double TiltD, double Dist, + bool IsRayOn, double Voltage, double Current ) : CncNode(Id, Index, CncNodeType.ReferencePoint, Name); /// 保存节点(含图像)| Save node with image @@ -113,4 +114,4 @@ namespace XplorePlane.Models DateTime UpdatedAt, IReadOnlyList Nodes ); -} \ No newline at end of file +} diff --git a/XplorePlane/Services/Cnc/CncProgramService.cs b/XplorePlane/Services/Cnc/CncProgramService.cs index c7f9524..eabad59 100644 --- a/XplorePlane/Services/Cnc/CncProgramService.cs +++ b/XplorePlane/Services/Cnc/CncProgramService.cs @@ -6,6 +6,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; using XP.Common.Logging.Interfaces; +using XP.Hardware.RaySource.Services; using XplorePlane.Models; using XplorePlane.Services.AppState; @@ -20,6 +21,7 @@ namespace XplorePlane.Services.Cnc public class CncProgramService : ICncProgramService { private readonly IAppStateService _appStateService; + private readonly IRaySourceService _raySourceService; private readonly ILoggerService _logger; // ── 序列化配置 | Serialization options ── @@ -32,12 +34,15 @@ namespace XplorePlane.Services.Cnc public CncProgramService( IAppStateService appStateService, + IRaySourceService raySourceService, ILoggerService logger) { ArgumentNullException.ThrowIfNull(appStateService); + ArgumentNullException.ThrowIfNull(raySourceService); ArgumentNullException.ThrowIfNull(logger); _appStateService = appStateService; + _raySourceService = raySourceService; _logger = logger.ForModule(); _logger.Info("CncProgramService 已初始化 | CncProgramService initialized"); @@ -344,6 +349,7 @@ namespace XplorePlane.Services.Cnc private ReferencePointNode CreateReferencePointNode(Guid id, int index) { var motion = _appStateService.MotionState; + var raySource = _appStateService.RaySourceState; return new ReferencePointNode( id, index, $"参考点_{index}", XM: motion.XM, @@ -351,7 +357,10 @@ namespace XplorePlane.Services.Cnc ZT: motion.ZT, ZD: motion.ZD, TiltD: motion.TiltD, - Dist: motion.Dist); + Dist: motion.Dist, + IsRayOn: raySource.IsOn, + Voltage: raySource.Voltage, + Current: TryReadCurrent()); } /// 创建保存节点(含图像)| Create save node with image @@ -382,5 +391,24 @@ namespace XplorePlane.Services.Cnc id, index, $"保存位置_{index}", MotionState: _appStateService.MotionState); } + private double TryReadCurrent() + { + try + { + var result = _raySourceService.ReadCurrent(); + if (result?.Success == true) + { + return result.GetFloat(); + } + + _logger.Warn("Failed to read ray source current, ReferencePoint node will use 0"); + } + catch (Exception ex) + { + _logger.Warn("Failed to read ray source current: {Message}", ex.Message); + } + + return 0d; + } } -} \ No newline at end of file +} diff --git a/XplorePlane/ViewModels/Cnc/CncEditorViewModel.cs b/XplorePlane/ViewModels/Cnc/CncEditorViewModel.cs index 325c9c2..c1cdc9c 100644 --- a/XplorePlane/ViewModels/Cnc/CncEditorViewModel.cs +++ b/XplorePlane/ViewModels/Cnc/CncEditorViewModel.cs @@ -173,7 +173,7 @@ namespace XplorePlane.ViewModels.Cnc if (_currentProgram == null) { _logger.Warn("无法插入节点:当前无程序 | Cannot insert node: no current program"); - return; + ExecuteNewProgram(); } try @@ -365,7 +365,7 @@ namespace XplorePlane.ViewModels.Cnc var sb = new StringBuilder(); // CSV 表头 | CSV header - sb.AppendLine("Index,NodeType,Name,XM,YM,ZT,ZD,TiltD,Dist,Voltage_kV,Power_W,RayOn,DetectorConnected,FrameRate,Resolution,ImageFile,MarkerType,MarkerX,MarkerY,DialogTitle,DialogMessage,DelayMs,Pipeline"); + sb.AppendLine("Index,NodeType,Name,XM,YM,ZT,ZD,TiltD,Dist,Voltage_kV,Current_uA,Power_W,RayOn,DetectorConnected,FrameRate,Resolution,ImageFile,MarkerType,MarkerX,MarkerY,DialogTitle,DialogMessage,DelayMs,Pipeline"); var inv = CultureInfo.InvariantCulture; @@ -373,11 +373,11 @@ namespace XplorePlane.ViewModels.Cnc { var row = node switch { - ReferencePointNode rp => $"{rp.Index},{rp.NodeType},{Esc(rp.Name)},{rp.XM.ToString(inv)},{rp.YM.ToString(inv)},{rp.ZT.ToString(inv)},{rp.ZD.ToString(inv)},{rp.TiltD.ToString(inv)},{rp.Dist.ToString(inv)},,,,,,,,,,,,,,", + ReferencePointNode rp => $"{rp.Index},{rp.NodeType},{Esc(rp.Name)},{rp.XM.ToString(inv)},{rp.YM.ToString(inv)},{rp.ZT.ToString(inv)},{rp.ZD.ToString(inv)},{rp.TiltD.ToString(inv)},{rp.Dist.ToString(inv)},{rp.Voltage.ToString(inv)},{rp.Current.ToString(inv)},,{rp.IsRayOn},,,,,,,,,,", - SaveNodeWithImageNode sni => $"{sni.Index},{sni.NodeType},{Esc(sni.Name)},{sni.MotionState.XM.ToString(inv)},{sni.MotionState.YM.ToString(inv)},{sni.MotionState.ZT.ToString(inv)},{sni.MotionState.ZD.ToString(inv)},{sni.MotionState.TiltD.ToString(inv)},{sni.MotionState.Dist.ToString(inv)},{sni.RaySourceState.Voltage.ToString(inv)},{sni.RaySourceState.Power.ToString(inv)},{sni.RaySourceState.IsOn},{sni.DetectorState.IsConnected},{sni.DetectorState.FrameRate.ToString(inv)},{Esc(sni.DetectorState.Resolution)},{Esc(sni.ImageFileName)},,,,,,", + SaveNodeWithImageNode sni => $"{sni.Index},{sni.NodeType},{Esc(sni.Name)},{sni.MotionState.XM.ToString(inv)},{sni.MotionState.YM.ToString(inv)},{sni.MotionState.ZT.ToString(inv)},{sni.MotionState.ZD.ToString(inv)},{sni.MotionState.TiltD.ToString(inv)},{sni.MotionState.Dist.ToString(inv)},{sni.RaySourceState.Voltage.ToString(inv)},,{sni.RaySourceState.Power.ToString(inv)},{sni.RaySourceState.IsOn},{sni.DetectorState.IsConnected},{sni.DetectorState.FrameRate.ToString(inv)},{Esc(sni.DetectorState.Resolution)},{Esc(sni.ImageFileName)},,,,,,", - SaveNodeNode sn => $"{sn.Index},{sn.NodeType},{Esc(sn.Name)},{sn.MotionState.XM.ToString(inv)},{sn.MotionState.YM.ToString(inv)},{sn.MotionState.ZT.ToString(inv)},{sn.MotionState.ZD.ToString(inv)},{sn.MotionState.TiltD.ToString(inv)},{sn.MotionState.Dist.ToString(inv)},{sn.RaySourceState.Voltage.ToString(inv)},{sn.RaySourceState.Power.ToString(inv)},{sn.RaySourceState.IsOn},{sn.DetectorState.IsConnected},{sn.DetectorState.FrameRate.ToString(inv)},{Esc(sn.DetectorState.Resolution)},,,,,,,", + SaveNodeNode sn => $"{sn.Index},{sn.NodeType},{Esc(sn.Name)},{sn.MotionState.XM.ToString(inv)},{sn.MotionState.YM.ToString(inv)},{sn.MotionState.ZT.ToString(inv)},{sn.MotionState.ZD.ToString(inv)},{sn.MotionState.TiltD.ToString(inv)},{sn.MotionState.Dist.ToString(inv)},{sn.RaySourceState.Voltage.ToString(inv)},,{sn.RaySourceState.Power.ToString(inv)},{sn.RaySourceState.IsOn},{sn.DetectorState.IsConnected},{sn.DetectorState.FrameRate.ToString(inv)},{Esc(sn.DetectorState.Resolution)},,,,,,,", SavePositionNode sp => $"{sp.Index},{sp.NodeType},{Esc(sp.Name)},{sp.MotionState.XM.ToString(inv)},{sp.MotionState.YM.ToString(inv)},{sp.MotionState.ZT.ToString(inv)},{sp.MotionState.ZD.ToString(inv)},{sp.MotionState.TiltD.ToString(inv)},{sp.MotionState.Dist.ToString(inv)},,,,,,,,,,,,,,", @@ -466,4 +466,4 @@ namespace XplorePlane.ViewModels.Cnc .Publish(new CncProgramChangedPayload(ProgramName ?? string.Empty, IsModified)); } } -} \ No newline at end of file +} diff --git a/XplorePlane/ViewModels/Main/MainViewModel.cs b/XplorePlane/ViewModels/Main/MainViewModel.cs index 2a97744..f3a633e 100644 --- a/XplorePlane/ViewModels/Main/MainViewModel.cs +++ b/XplorePlane/ViewModels/Main/MainViewModel.cs @@ -10,6 +10,7 @@ using System.IO; using System.Windows; using System.Windows.Media.Imaging; using XplorePlane.Events; +using XplorePlane.ViewModels.Cnc; using XplorePlane.Views; using XplorePlane.Views.Cnc; using XP.Common.Logging.Interfaces; @@ -23,6 +24,8 @@ namespace XplorePlane.ViewModels private readonly ILoggerService _logger; private readonly IContainerProvider _containerProvider; private readonly IEventAggregator _eventAggregator; + private readonly CncEditorViewModel _cncEditorViewModel; + private readonly CncPageView _cncPageView; private string _licenseInfo = "当前时间"; public string LicenseInfo @@ -51,6 +54,17 @@ namespace XplorePlane.ViewModels public DelegateCommand OpenLibraryVersionsCommand { get; } public DelegateCommand OpenUserManualCommand { get; } public DelegateCommand OpenCameraSettingsCommand { get; } + public DelegateCommand NewCncProgramCommand { get; } + public DelegateCommand SaveCncProgramCommand { get; } + public DelegateCommand LoadCncProgramCommand { get; } + public DelegateCommand InsertReferencePointCommand { get; } + public DelegateCommand InsertSavePositionCommand { get; } + public DelegateCommand InsertCompleteProgramCommand { get; } + public DelegateCommand InsertInspectionMarkerCommand { get; } + public DelegateCommand InsertInspectionModuleCommand { get; } + public DelegateCommand InsertSaveNodeCommand { get; } + public DelegateCommand InsertPauseDialogCommand { get; } + public DelegateCommand InsertWaitDelayCommand { get; } // 硬件命令 public DelegateCommand AxisResetCommand { get; } @@ -94,6 +108,8 @@ namespace XplorePlane.ViewModels _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); _containerProvider = containerProvider ?? throw new ArgumentNullException(nameof(containerProvider)); _eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator)); + _cncEditorViewModel = _containerProvider.Resolve(); + _cncPageView = new CncPageView { DataContext = _cncEditorViewModel }; NavigationTree = new ObservableCollection(); @@ -115,6 +131,17 @@ namespace XplorePlane.ViewModels OpenLibraryVersionsCommand = new DelegateCommand(() => ShowWindow(new Views.LibraryVersionsWindow(), "关于")); OpenUserManualCommand = new DelegateCommand(ExecuteOpenUserManual); OpenCameraSettingsCommand = new DelegateCommand(ExecuteOpenCameraSettings); + NewCncProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.NewProgramCommand.Execute())); + SaveCncProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.SaveProgramCommand.Execute())); + LoadCncProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.LoadProgramCommand.Execute())); + InsertReferencePointCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertReferencePointCommand.Execute())); + InsertSavePositionCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertSavePositionCommand.Execute())); + InsertCompleteProgramCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertCompleteProgramCommand.Execute())); + InsertInspectionMarkerCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertInspectionMarkerCommand.Execute())); + InsertInspectionModuleCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertInspectionModuleCommand.Execute())); + InsertSaveNodeCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertSaveNodeCommand.Execute())); + InsertPauseDialogCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertPauseDialogCommand.Execute())); + InsertWaitDelayCommand = new DelegateCommand(() => ExecuteCncEditorAction(vm => vm.InsertWaitDelayCommand.Execute())); // 硬件命令 AxisResetCommand = new DelegateCommand(ExecuteAxisReset); @@ -186,7 +213,20 @@ namespace XplorePlane.ViewModels return; } - ImagePanelContent = new CncPageView(); + ShowCncEditor(); + } + + private void ExecuteCncEditorAction(Action action) + { + ArgumentNullException.ThrowIfNull(action); + + ShowCncEditor(); + action(_cncEditorViewModel); + } + + private void ShowCncEditor() + { + ImagePanelContent = _cncPageView; ImagePanelWidth = new GridLength(430); _isCncEditorMode = true; _logger.Info("CNC 编辑器已切换到主界面图像区域"); diff --git a/XplorePlane/Views/Cnc/CncPageView.xaml b/XplorePlane/Views/Cnc/CncPageView.xaml index cb9b5a3..10a3fd8 100644 --- a/XplorePlane/Views/Cnc/CncPageView.xaml +++ b/XplorePlane/Views/Cnc/CncPageView.xaml @@ -53,7 +53,8 @@ - + @@ -82,11 +82,12 @@ telerik:ScreenTip.Description="保存当前X射线实时图像" telerik:ScreenTip.Title="保存图像" Size="Medium" + Command="{Binding SaveCncProgramCommand}" SmallImage="/Assets/Icons/save.png" Text="保存" /> @@ -94,7 +95,7 @@ @@ -293,16 +294,19 @@ @@ -310,16 +314,19 @@ @@ -327,11 +334,13 @@