刘锦天 8 months ago
parent
commit
f0a0e142f3

+ 147 - 8
TeamAAS-VM/Core/Management.cs

@@ -1230,18 +1230,78 @@ namespace TeamAAS_VP.Core
                     {
                     {
                         if (state)
                         if (state)
                         {
                         {
-                            SendTaskMessage($"触发固定相机取料拍照...", MessageLevel.Debug);
+                            SendTaskMessage($"触发固定相机检测拍照...", MessageLevel.Debug);
                             //相机的编号
                             //相机的编号
-                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameraPickNum.Address);
+                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
+                            // 读取相机编号
 
 
+                            Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
+                            SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
 
 
+                            // 找到对应编号的 PlcPoint
+                            var targetPoint = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex);
+                            if (targetPoint == null)
+                            {
+                                SendTaskMessage($"未找到 AOI 点位,编号:{cameraIndex}", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
+                                return;
+                            }
 
 
-                            await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
+                            // CameraProcedureId 存储的是具体的视觉流程 Id(ProcedureModel.Id),
+                            // 需要在所有 CameraProcedures 的 ProcedureModels 中查找匹配的流程。
+                            ProcedureModel selectedProcedure = null;
+                            try
+                            {
+                                var cameraProcedures = currentProduct.CameraProcedures;
+                                if (cameraProcedures != null)
+                                {
+                                    foreach (var cp in cameraProcedures)
+                                    {
+                                        if (cp?.ProcedureModels == null) continue;
+                                        selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == targetPoint.CameraProcedureId);
+                                        if (selectedProcedure != null) break;
+                                    }
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
+                            }
+
+                            if (selectedProcedure == null)
+                            {
+                                SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{cameraIndex} ProcedureId={targetPoint.CameraProcedureId}", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
+                                return;
+                            }
+
+                            // 执行选中的视觉流程
+                            try
+                            {
+                                var cts = new CancellationTokenSource();
+                                var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(selectedProcedure, null, null, cts.Token);
+                                if (visionResult.IsSucceed)
+                                {
+                                    SendTaskMessage($"AOI 流程执行成功:X={visionResult.X:F3} Y={visionResult.Y:F3}", MessageLevel.Info);
+                                    await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
+                                }
+                                else
+                                {
+                                    SendTaskMessage($"AOI 流程执行失败:Point#{cameraIndex}", MessageLevel.Alarm);
+                                    await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                LogHelper.WriteLogError("执行 AOI 视觉流程时出错", ex);
+                                SendTaskMessage($"执行 AOI 视觉流程异常: {ex.Message}", MessageLevel.Alarm);
+                                try { await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2); } catch { }
+                            }
                         }
                         }
                         else
                         else
                         {
                         {
-                            SendTaskMessage($"触发固定相机取料拍照信号已关闭", MessageLevel.Alarm);
-                            await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)0);
+                            SendTaskMessage($"触发固定相机检测拍照信号已关闭", MessageLevel.Alarm);
+                            await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)0);
                         }
                         }
                     }
                     }
                 }
                 }
@@ -1274,11 +1334,90 @@ namespace TeamAAS_VP.Core
                         if (state)
                         if (state)
                         {
                         {
                             SendTaskMessage($"触发固定相机检测拍照...", MessageLevel.Debug);
                             SendTaskMessage($"触发固定相机检测拍照...", MessageLevel.Debug);
-                            //相机的编号
-                            //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
+                            // 读取相机编号
+                            
+                            Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
+                            SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
+
+                            // 直接遍历 CameraProcedures,查找名称为 "C{cameraIndex}" 的流程(不保存回退)
+                            string targetName = $"C{cameraIndex}";
+                            object selectedProcess = null;
+                            try
+                            {
+                                var cameraProcedures = currentProduct.CameraProcedures;
+                                if (cameraProcedures != null)
+                                {
+                                    foreach (var cp in cameraProcedures)
+                                    {
+                                        var pmProp = cp.GetType().GetProperty("ProcedureModels");
+                                        if (pmProp == null) continue;
+                                        var pms = pmProp.GetValue(cp) as IEnumerable;
+                                        if (pms == null) continue;
+
+                                        foreach (var pm in pms)
+                                        {
+                                            var nameProp = pm.GetType().GetProperty("Name")
+                                                           ?? pm.GetType().GetProperty("ProcedureName")
+                                                           ?? pm.GetType().GetProperty("CameraName");
+                                            var name = nameProp?.GetValue(pm)?.ToString() ?? string.Empty;
+
+                                            if (string.Equals(name, targetName, StringComparison.OrdinalIgnoreCase))
+                                            {
+                                                selectedProcess = pm;
+                                                SendTaskMessage($"按名称匹配到流程: {name}", MessageLevel.Debug);
+                                                break;
+                                            }
+                                        }
+
+                                        if (selectedProcess != null) break;
+                                    }
+                                }
+
+                                if (selectedProcess == null)
+                                {
+                                    SendTaskMessage("未找到任何拍照流程,写入失败状态。", MessageLevel.Alarm);
+                                    await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
+                                    return;
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                LogHelper.WriteLogError("查找拍照流程时出错", ex);
+                                SendTaskMessage($"查找拍照流程时出错: {ex.Message}", MessageLevel.Alarm);
+                                await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
+                                return;
+                            }
 
 
+                            // 执行选中的视觉流程
+                            try
+                            {
+                                var cts = new CancellationTokenSource();
+                                // 参数:根据当前流程需要,第二/第三参数可调整(这里保持 null)
+                                var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(selectedProcess as ProcedureModel, null, null, cts.Token);
 
 
-                            await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
+                                if (visionResult.IsSucceed)
+                                {
+                                    SendTaskMessage($"流程 {targetName} 执行成功:X={visionResult.X:F3} Y={visionResult.Y:F3}", MessageLevel.Info);
+                                    // 写回 PLC 成功状态
+                                    await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
+
+                                    // 如果需要把坐标写回 PLC,请在这里添加对应地址写入(Out_* 字段需在 PlcAddressConfig 中存在)
+                                    // 例如:
+                                    // await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPick_X.Address, (float)visionResult.X);
+                                    // await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPick_Y.Address, (float)visionResult.Y);
+                                }
+                                else
+                                {
+                                    SendTaskMessage($"流程 {targetName} 执行失败。", MessageLevel.Alarm);
+                                    await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                LogHelper.WriteLogError("执行拍照流程时出错", ex);
+                                SendTaskMessage($"执行拍照流程异常: {ex.Message}", MessageLevel.Alarm);
+                                try { await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2); } catch { }
+                            }
                         }
                         }
                         else
                         else
                         {
                         {

+ 7 - 4
TeamAAS-VM/Core/Robots/XYZU_Robot.cs

@@ -373,8 +373,11 @@ namespace TeamAAS_VP.Core.Robots
 
 
         public bool Move(RPoint position) => Go(position);
         public bool Move(RPoint position) => Go(position);
         public Task<bool> MoveAsync(RPoint position) => GoAsync(position);
         public Task<bool> MoveAsync(RPoint position) => GoAsync(position);
-        public bool Jump(RPoint position, double? LimZ) => Go(position);
-        public Task<bool> JumpAsync(RPoint position, double? LimZ) => GoAsync(position);
+        public bool Jump(RPoint position, double? LimZ)
+        {
+            return CalibMotion(position, LimZ);
+        }
+        public Task<bool> JumpAsync(RPoint position, double? LimZ) => CalibMotionAsync(position, LimZ);
         public bool Jog(string axis, double distance)
         public bool Jog(string axis, double distance)
         {
         {
             //获取当前机器人坐标
             //获取当前机器人坐标
@@ -455,7 +458,7 @@ namespace TeamAAS_VP.Core.Robots
                     if (string.IsNullOrWhiteSpace(axis.Parameter.ManuVelocityNode)) continue;
                     if (string.IsNullOrWhiteSpace(axis.Parameter.ManuVelocityNode)) continue;
                     string nodeid = axis.Parameter.ManuVelocityNode;
                     string nodeid = axis.Parameter.ManuVelocityNode;
                     float value = Speed;
                     float value = Speed;
-                    
+
                     keyValues.Add(nodeid, value);
                     keyValues.Add(nodeid, value);
                 }
                 }
                 // 2. 写入速度给所有轴
                 // 2. 写入速度给所有轴
@@ -582,7 +585,7 @@ namespace TeamAAS_VP.Core.Robots
                     }
                     }
 
 
                     // 判断是否至少有一个轴在最近 Timeout 时间内发生过变化(即认为还在运动)
                     // 判断是否至少有一个轴在最近 Timeout 时间内发生过变化(即认为还在运动)
-                    bool anyAxisMovedRecently = actNodes.Any(node => (now - lastChange[node]).TotalMilliseconds <= Timeout);
+                    bool anyAxisMovedRecently = actNodes.Any(node => (now - lastChange[node]).TotalMilliseconds <= 1000);
 
 
                     // 如果没有任何轴在最近 Timeout 时间内发生变化,则认为出现停滞异常
                     // 如果没有任何轴在最近 Timeout 时间内发生变化,则认为出现停滞异常
                     if (!anyAxisMovedRecently && actNodes.Length > 0)
                     if (!anyAxisMovedRecently && actNodes.Length > 0)

+ 10 - 1
TeamAAS-VM/Models/PLC/PlcPoint.cs

@@ -192,7 +192,15 @@ namespace TeamAAS_VP.Models.PLC
             get { return _Enable_Light4; }
             get { return _Enable_Light4; }
             set { SetProperty(ref _Enable_Light4, value); }
             set { SetProperty(ref _Enable_Light4, value); }
         }
         }
-
+        private Guid _CameraProcedureId = Guid.Empty;
+        /// <summary>
+        /// Camera 对应的视觉流程 Id
+        /// </summary>
+        public Guid CameraProcedureId
+        {
+            get { return _CameraProcedureId; }
+            set { SetProperty(ref _CameraProcedureId, value); }
+        }
         private float _R_Position;
         private float _R_Position;
         public float R_Position
         public float R_Position
         {
         {
@@ -303,6 +311,7 @@ namespace TeamAAS_VP.Models.PLC
                 Enable_Light2 = this.Enable_Light2,
                 Enable_Light2 = this.Enable_Light2,
                 Enable_Light3 = this.Enable_Light3,
                 Enable_Light3 = this.Enable_Light3,
                 Enable_Light4 = this.Enable_Light4,
                 Enable_Light4 = this.Enable_Light4,
+                CameraProcedureId = this.CameraProcedureId,
                 //R_Position = this.R_Position,
                 //R_Position = this.R_Position,
                 //R_Velocity = this.R_Velocity,
                 //R_Velocity = this.R_Velocity,
                 //Torque = this.Torque,
                 //Torque = this.Torque,

+ 5 - 5
TeamAAS-VM/ViewModels/MainWindowViewModel.cs

@@ -340,11 +340,11 @@ namespace TeamAAS_VP.ViewModels
 
 
             //-------------------SETP 7: 初始化电批-----------------------------------------------------------------------
             //-------------------SETP 7: 初始化电批-----------------------------------------------------------------------
             curvalue += 1;
             curvalue += 1;
-            _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
-            {
-                _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = max, Minimum = 0, SubTitle = $"{Lang.初始化中}...", Message = $"正在连接电批...", Value = curvalue });
-            }));
-            await management.InitScrewDriver();
+            //_ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
+            //{
+            //    _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = max, Minimum = 0, SubTitle = $"{Lang.初始化中}...", Message = $"正在连接电批...", Value = curvalue });
+            //}));
+            //await management.InitScrewDriver();
 
 
             //-------------------SETP 8: 加载所有产品-----------------------------------------------------------------------
             //-------------------SETP 8: 加载所有产品-----------------------------------------------------------------------
             curvalue += 1;
             curvalue += 1;

+ 379 - 4
TeamAAS-VM/ViewModels/Product/PlcPointParamsViewModel.cs

@@ -1,4 +1,5 @@
-using MaterialDesignThemes.Wpf;
+using Cognex.VisionPro;
+using MaterialDesignThemes.Wpf;
 using MathNet.Numerics.LinearAlgebra;
 using MathNet.Numerics.LinearAlgebra;
 using Prism.Commands;
 using Prism.Commands;
 using Prism.Events;
 using Prism.Events;
@@ -9,6 +10,7 @@ using Prism.Services.Dialogs;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.ObjectModel;
+using System.Drawing;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -40,6 +42,9 @@ namespace TeamAAS_VP.ViewModels.Product
         IRobotService _robotService;
         IRobotService _robotService;
         ISystemDatabaseService _systemDatabaseService;
         ISystemDatabaseService _systemDatabaseService;
         IRemoteCommandService _remoteCommandService;
         IRemoteCommandService _remoteCommandService;
+        ICalibrationService _calibrationService;
+        ICameraService _cameraService;
+        CoordinateTransformer local = null;
 
 
         #region 属性
         #region 属性
 
 
@@ -278,7 +283,81 @@ namespace TeamAAS_VP.ViewModels.Product
             get { return _LockScrewProgramNumber; }
             get { return _LockScrewProgramNumber; }
             set { SetProperty(ref _LockScrewProgramNumber, value); }
             set { SetProperty(ref _LockScrewProgramNumber, value); }
         }
         }
+        private bool _IsGrap;
+        public bool IsGrap
+        {
+            get { return _IsGrap; }
+            set { SetProperty(ref _IsGrap, value); }
+        }
+
+        private ObservableCollection<CameraInfo> _CameraList;
+        public ObservableCollection<CameraInfo> CameraList
+        {
+            get { return _CameraList; }
+            set { SetProperty(ref _CameraList, value); }
+        }
+
+        private CameraInfo _SelectedCamera;
+        public CameraInfo SelectedCamera
+        {
+            get { return _SelectedCamera; }
+            set
+            {
+                SetProperty(ref _SelectedCamera, value);
+                if (value != null)
+                {
+                    if (Camera != null)
+                    {
+                        if (Camera.IsGrabbing)
+                        {
+                            Camera.StopGrabbing();
+                        }
+                        Camera.ImageCallbackEvent -= Camera_ImageCallbackEvent;
+                    }
+                    Camera = _cameraService.GetCamera(value.Id);
+                    Camera.ImageCallbackEvent += Camera_ImageCallbackEvent;
+                }
+            }
+        }
+
+        private ICamera _Camera;
+        public ICamera Camera
+        {
+            get { return _Camera; }
+            set { SetProperty(ref _Camera, value); }
+        }
+
+        private ICogImage _Image;
 
 
+        public ICogImage Image
+        {
+            get { return _Image; }
+            set { SetProperty(ref _Image, value); }
+        }
+
+        private string _Message;
+        public string Message
+        {
+            get { return _Message; }
+            set { SetProperty(ref _Message, value); }
+        }
+
+        private bool _IsLeftDrawerOpen;
+        public bool IsLeftDrawerOpen
+        {
+            get { return _IsLeftDrawerOpen; }
+            set
+            {
+                SetProperty(ref _IsLeftDrawerOpen, value);
+                if (!value)
+                {
+                    if (IsGrap)
+                    {
+                        ExecuteStopGrabbingCommand();
+                    }
+                }
+            }
+        }
         #endregion
         #endregion
 
 
         #region 命令
         #region 命令
@@ -368,6 +447,13 @@ namespace TeamAAS_VP.ViewModels.Product
         private DelegateCommand _AutoCorrectLockPointCommand;
         private DelegateCommand _AutoCorrectLockPointCommand;
         public DelegateCommand AutoCorrectLockPointCommand =>
         public DelegateCommand AutoCorrectLockPointCommand =>
             _AutoCorrectLockPointCommand ?? (_AutoCorrectLockPointCommand = new DelegateCommand(ExecuteAutoCorrectLockPoint));
             _AutoCorrectLockPointCommand ?? (_AutoCorrectLockPointCommand = new DelegateCommand(ExecuteAutoCorrectLockPoint));
+        private DelegateCommand _StartGrabbingCommand;
+        public DelegateCommand StartGrabbingCommand =>
+            _StartGrabbingCommand ?? (_StartGrabbingCommand = new DelegateCommand(ExecuteStartGrabbingCommand, CanExecuteStartGrabbingCommand).ObservesProperty(() => IsGrap).ObservesProperty(() => SelectedCamera));
+
+        private DelegateCommand _StopGrabbingCommand;
+        public DelegateCommand StopGrabbingCommand =>
+            _StopGrabbingCommand ?? (_StopGrabbingCommand = new DelegateCommand(ExecuteStopGrabbingCommand, CanExecuteStopGrabbingCommand).ObservesProperty(() => IsGrap).ObservesProperty(() => SelectedCamera));
 
 
         #endregion
         #endregion
 
 
@@ -376,7 +462,8 @@ namespace TeamAAS_VP.ViewModels.Product
         #endregion
         #endregion
 
 
         public PlcPointParamsViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IDialogService dialogService,
         public PlcPointParamsViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IDialogService dialogService,
-            IConfigService configService, IRobotService robotService, ISystemDatabaseService systemDatabaseService, IRemoteCommandService remoteCommandService)
+            IConfigService configService, IRobotService robotService, ISystemDatabaseService systemDatabaseService, IRemoteCommandService remoteCommandService,
+            ICalibrationService calibrationService, ICameraService cameraService)
         {
         {
             _regionManager = regionManager;
             _regionManager = regionManager;
             _eventAggregator = ea;
             _eventAggregator = ea;
@@ -389,6 +476,8 @@ namespace TeamAAS_VP.ViewModels.Product
             management = _container.Resolve<Management>();
             management = _container.Resolve<Management>();
             _robotService = robotService;
             _robotService = robotService;
             _remoteCommandService = remoteCommandService;
             _remoteCommandService = remoteCommandService;
+            _calibrationService = calibrationService;
+            _cameraService = cameraService;
         }
         }
 
 
         #region 方法
         #region 方法
@@ -1115,6 +1204,285 @@ namespace TeamAAS_VP.ViewModels.Product
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
                 _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
             }
             }
         }
         }
+
+        /// <summary>
+        /// 通过相机先定位产品再执行锁付点位
+        /// </summary>
+        /// <param name="point"></param>
+        private async Task ExecuteAutoCorrectLockPointAndExecuteCommand(PlcPoint point)
+        {
+            var waiting = new WaitingControl();
+            Task<object> task;
+            try
+            {
+                if (Robot == null || !Robot.IsConnected) return;
+                //弹窗提示用户是否确认要通过相机自动矫正锁附点位并执行该点位
+                var resultConfirm = MessageBox.Show($"确认要通过相机自动矫正锁附点位并执行点位 {point.Number} 吗?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
+                if (resultConfirm != MessageBoxResult.Yes)
+                {
+                    return;
+                }
+
+
+                if (Robot == null || !Robot.IsConnected)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "机器人未连接,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return;
+                }
+                //获取当前产品
+                var product = SelectProduct;
+                if (product == null)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未选择产品,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return;
+                }
+
+
+
+                //如果当前Local为空,则自动进行锁付点位的Local计算
+                if (local == null)
+                {
+                    //show the dialog
+                    task = DialogHost.Show(waiting, "RootDialog", null, null, null);
+                    var isCalibSucceed = await AutoCalibLockPointLocal(product);
+                    if (!isCalibSucceed)
+                    {
+                        return;
+                    }
+                }
+                else
+                {
+                    //提示用户,当前系统检测到进入此界面后已经进行过相机产品定位并计算过Local,是否继续使用该Local进行锁付点位的转换计算
+                    var resultUseExistingLocal = MessageBox.Show("系统检测到进入此界面后已经进行过相机产品定位并计算过Local,是否继续使用该Local进行锁付点位的转换计算?点击“是”继续使用,点击“否”则重新进行锁付点位的Local计算。", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
+                    if (resultUseExistingLocal == MessageBoxResult.No)
+                    {
+                        //show the dialog
+                        task = DialogHost.Show(waiting, "RootDialog", null, null, null);
+                        var isCalibSucceed = await AutoCalibLockPointLocal(product);
+                        if (!isCalibSucceed)
+                        {
+                            return;
+                        }
+                    }
+                    else
+                    {
+                        //show the dialog
+                        task = DialogHost.Show(waiting, "RootDialog", null, null, null);
+                    }
+                }
+
+                //将锁付点位转换到世界坐标系
+                var localPoint = new PointF(point.X_Position_Start, point.Y_Position_Start);
+                var worldPoint = local.ToOldCoord(localPoint.X, localPoint.Y);
+                var point1 = point.Clone();
+                point1.X_Position_Start = (float)worldPoint[0];
+                point1.Y_Position_Start = (float)worldPoint[1];
+                //执行该点位
+                //移动机器人至拍照点位,拍照
+                var rpoint = new RPoint()
+                {
+                    X = point.X_Position_Start,
+                    Y = point.Y_Position_Start,
+                    Z = point.Z_Position_Start,
+                };
+                await Robot.CalibMotionAsync(rpoint, 0);
+
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "完成!", Duration = 1 });
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("通过相机自动矫正锁附点位并执行时出错!", ex);
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
+            }
+            finally
+            {
+                try
+                {
+                    if (DialogHost.IsDialogOpen("RootDialog"))
+                    {
+                        DialogHost.Close("RootDialog");
+                    }
+                }
+                catch (Exception)
+                {
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 移动相机拍产品两个Msrk点计算Local
+        /// </summary>
+        /// <param name="product"></param>
+        /// <returns></returns>
+        private async Task<bool> AutoCalibLockPointLocal(ProductModel product)
+        {
+            try
+            {
+                //获取锁付相机拍照点位
+                var screwCameraPoint = product.ScrewCameraPoints;
+                if (screwCameraPoint == null || screwCameraPoint.Count < 2)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照点位,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return false;
+                }
+                //获取相机拍照点位对应的锁付点
+                var screwCameraLocalPoint1 = product.ScrewCameraLocalPos1;
+                if (screwCameraLocalPoint1 == null)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照点位对应的锁付点,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return false;
+                }
+                var screwCameraLocalPoint2 = product.ScrewCameraLocalPos2;
+                if (screwCameraLocalPoint2 == null)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照点位对应的锁付点,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return false;
+                }
+                var ProcedureModels = new ObservableCollection<ProcedureModel>();
+                foreach (var item in product.CameraProcedures)
+                {
+                    foreach (var item1 in item.ProcedureModels)
+                    {
+                        ProcedureModels.Add(item1);
+                    }
+                }
+                //获取拍照流程
+                if (product.MoveDownCameraLockPhotoProcedureId == Guid.Empty)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照流程,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return false;
+                }
+                var procedure = ProcedureModels.FirstOrDefault(p => p.Id == product.MoveDownCameraLockPhotoProcedureId);
+                if (procedure == null)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照流程,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return false;
+                }
+
+                CancellationTokenSource _cts = new CancellationTokenSource();
+                //移动机器人至拍照点位,拍照
+                var rpoint = new RPoint()
+                {
+                    X = screwCameraPoint[0].X_Position_Start,
+                    Y = screwCameraPoint[0].Y_Position_Start,
+                    Z = screwCameraPoint[0].Z_Position_Start,
+                    U = screwCameraPoint[0].U_Position_Start,
+                    V = screwCameraPoint[0].R_Position,
+                };
+                await Robot.CalibMotionAsync(rpoint, 0);
+                await Task.Delay(200);
+                // 执行拍照并获取识别结果
+                var recognitionResult = await _remoteCommandService.ExecutePhotoGetSinglePointWithImage(procedure, null, new double[] { rpoint.X, rpoint.Y, 0 }, _cts.Token);
+                //var Image = recognitionResult.Image;
+                //var Graphic = null;
+                //var Graphic = recognitionResult.Graphic;
+                if (!recognitionResult.IsSucceed)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "拍照获取识别结果失败,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return false;
+                }
+                //第一个点位的校正结果
+                PointF worldP1 = new PointF((float)recognitionResult.X, (float)recognitionResult.Y);
+                //移动机器人至拍照点位,拍照
+                rpoint = new RPoint()
+                {
+                    X = screwCameraPoint[1].X_Position_Start,
+                    Y = screwCameraPoint[1].Y_Position_Start,
+                    Z = screwCameraPoint[1].Z_Position_Start,
+                    U = screwCameraPoint[1].U_Position_Start,
+                    V = screwCameraPoint[1].R_Position,
+                };
+                await Robot.CalibMotionAsync(rpoint, 0);
+                if (_cts.IsCancellationRequested)
+                    return false;
+                await Task.Delay(200);
+                // 执行拍照并获取识别结果
+                recognitionResult = await _remoteCommandService.ExecutePhotoGetSinglePointWithImage(procedure, null, new double[] { rpoint.X, rpoint.Y, 0 }, _cts.Token);
+                //Image = recognitionResult.Image;
+                //Graphic = null;
+                //Graphic = recognitionResult.Graphic;
+                if (!recognitionResult.IsSucceed)
+                {
+                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "拍照获取识别结果失败,无法执行取料拍照点位矫正!", Duration = 1 });
+                    return false;
+                }
+                //第一个点位的校正结果
+                PointF worldP2 = new PointF((float)recognitionResult.X, (float)recognitionResult.Y);
+
+                //计算移动相机与拍照点之间的偏差
+                //获取校准
+                var calibration = _calibrationService.GetCalibration(procedure.CalibrationId);
+
+                //获取mark点
+                var mark = calibration.MarkPoint;
+                //获取中心点
+                var center = calibration.CenterPoint;
+                //计算相机中心与披头之间的坐标偏差
+                var cameraOffsetX = mark.X - center.X;
+                var cameraOffsetY = mark.Y - center.Y;
+
+
+                //根据UpCameraPutResults[]中的索引1、2,和拍照点对应的Local下的坐标,从创建Local坐标系
+                PointF localP1 = new PointF(screwCameraLocalPoint1.X_Position_Start, screwCameraLocalPoint1.Y_Position_Start);
+                PointF localP2 = new PointF(screwCameraLocalPoint2.X_Position_Start, screwCameraLocalPoint2.Y_Position_Start);
+                local = new CoordinateTransformer(worldP1, worldP2, localP1, localP2);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("计算锁付点位产品坐标系坐标时出错!", ex);
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 停止采集
+        /// </summary>
+        void ExecuteStopGrabbingCommand()
+        {
+
+            if (Camera != null)
+                Camera.StopGrabbing();
+            IsGrap = false;
+        }
+
+        bool CanExecuteStopGrabbingCommand()
+        {
+            return IsGrap;
+        }
+
+        /// <summary>
+        /// 开始采集
+        /// </summary>
+        void ExecuteStartGrabbingCommand()
+        {
+            if (Camera != null)
+                Camera.StartGrabbing();
+            IsGrap = true;
+        }
+        bool CanExecuteStartGrabbingCommand()
+        {
+            return SelectedCamera != null && !IsGrap;
+        }
+
+        private void Camera_ImageCallbackEvent(ICogImage image, TimeSpan totaltime, string errormessage)
+        {
+            Image = image;
+            App.Current.Dispatcher.Invoke(new
+                 Action(() =>
+                 {
+                     if (errormessage != null && !string.IsNullOrEmpty(errormessage))
+                     {
+                         Message = $"{Lang.耗时}:{totaltime.TotalMilliseconds.ToString("F1")} ms Error:{errormessage}";
+                     }
+                     else
+                     {
+                         Message = $"{Lang.耗时}:{totaltime.TotalMilliseconds.ToString("F1")} ms";
+                     }
+                 }));
+        }
         #endregion
         #endregion
 
 
         #region 继承
         #region 继承
@@ -1139,9 +1507,14 @@ namespace TeamAAS_VP.ViewModels.Product
             {
             {
                 SelectProduct = navigationContext.Parameters.GetValue<ProductModel>("SelectProduct");
                 SelectProduct = navigationContext.Parameters.GetValue<ProductModel>("SelectProduct");
 
 
-                SelectedIndex = 0;
+
+                // 默认选择 AOI 点位(索引 6),并初始化 Points
+                SelectedIndex = 6;
                 PickPoints = SelectProduct.PickPoints;
                 PickPoints = SelectProduct.PickPoints;
-                Points = SelectProduct.PickCameraPoints;
+                Points = SelectProduct.AoiPoints;
+                // 默认选中第一个点(如果存在)
+                SelectedPointInDataGrid = Points?.FirstOrDefault();
+                SelectedPointInComboBox = SelectedPointInDataGrid;
 
 
                 if (Robot == null)
                 if (Robot == null)
                 {
                 {
@@ -1175,6 +1548,8 @@ namespace TeamAAS_VP.ViewModels.Product
                 LockZDescendSpeed= SelectProduct.ScrewPoints.FirstOrDefault()?.Z_Velocity_Stop ?? 100;
                 LockZDescendSpeed= SelectProduct.ScrewPoints.FirstOrDefault()?.Z_Velocity_Stop ?? 100;
                 LockFeederNumber= SelectProduct.ScrewPoints.FirstOrDefault()?.Feeder ?? 1;
                 LockFeederNumber= SelectProduct.ScrewPoints.FirstOrDefault()?.Feeder ?? 1;
                 LockScrewProgramNumber= SelectProduct.ScrewPoints.FirstOrDefault()?.ScrewProNum ?? 1;
                 LockScrewProgramNumber= SelectProduct.ScrewPoints.FirstOrDefault()?.ScrewProNum ?? 1;
+
+                CameraList = new ObservableCollection<CameraInfo>(_configService.GetAllCameras());
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {

+ 106 - 17
TeamAAS-VM/Views/Product/PlcPointParams.xaml

@@ -2,6 +2,8 @@
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:prism="http://prismlibrary.com/"
              xmlns:prism="http://prismlibrary.com/"
+             xmlns:wf="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
+             xmlns:vp="clr-namespace:Cognex.VisionPro;assembly=Cognex.VisionPro.Controls"
              xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
              xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
              xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
              xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
              xmlns:sys="clr-namespace:System;assembly=mscorlib"
              xmlns:sys="clr-namespace:System;assembly=mscorlib"
@@ -95,12 +97,66 @@
         </Border>
         </Border>
 
 
         <materialDesign:DrawerHost Grid.Row="1"
         <materialDesign:DrawerHost Grid.Row="1"
-                                   OpenMode="Modal"
-                                   x:Name="DrawerHost"
-                                   IsEnabled="{Binding IsAllowEdit}">
-            <!--<materialDesign:DrawerHost.RightDrawerContent>
-            <local:TestProductPage Visibility="{Binding IsHaveRobot,Converter={StaticResource BooleanToVisibilityConverter}}" />
-        </materialDesign:DrawerHost.RightDrawerContent>-->
+                                   OpenMode="Standard"
+                                    x:Name="DrawerHost"
+                                    IsLeftDrawerOpen="{Binding IsLeftDrawerOpen,Mode=TwoWay}"
+                                    d:IsLeftDrawerOpen="true"
+                                    IsEnabled="{Binding IsAllowEdit}">
+            <materialDesign:DrawerHost.LeftDrawerContent>
+                <Grid Width="600">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="*" />
+                        <RowDefinition Height=" auto" />
+                    </Grid.RowDefinitions>
+                    <wf:WindowsFormsHost Grid.Row="0"
+                 Margin="0,40">
+                        <vp:CogRecordDisplay x:Name="display" />
+                    </wf:WindowsFormsHost>
+                    <StackPanel Grid.Row="1"
+        HorizontalAlignment="Left"
+        VerticalAlignment="Bottom"
+        Orientation="Horizontal">
+                        <TextBlock Text="{lex:Loc 相机,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}"
+           FontWeight="Bold"
+           VerticalAlignment="Center"
+           />
+                        <ComboBox Margin="5,0,10,0"
+          IsEnabled="{Binding IsGrap,Converter={StaticResource InvertBooleanConverter}}"
+          ItemsSource="{Binding CameraList}"
+          SelectedItem="{Binding SelectedCamera}"
+          materialDesign:HintAssist.Hint="{lex:Loc 选择相机}">
+                            <ComboBox.ItemTemplate>
+                                <DataTemplate>
+                                    <StackPanel Orientation="Horizontal">
+                                        <materialDesign:PackIcon Kind="Camera" />
+                                        <TextBlock Text="{Binding CameraName}"
+                           Margin="6,0" />
+                                    </StackPanel>
+                                </DataTemplate>
+                            </ComboBox.ItemTemplate>
+                        </ComboBox>
+                        <Button Grid.Column="0"
+        Content="{lex:Loc 开始采集}"
+        MinWidth="100"
+        materialDesign:ButtonAssist.CornerRadius="10"
+        Style="{StaticResource MaterialDesignRaisedButton}"
+        Command="{Binding StartGrabbingCommand}" />
+                        <Button Grid.Column="0"
+        Content="{lex:Loc 停止采集}"
+        IsEnabled="{Binding IsAllowEdit}"
+        MinWidth="100"
+        Margin="10,0"
+        materialDesign:ButtonAssist.CornerRadius="10"
+        Style="{StaticResource MaterialDesignRaisedButton}"
+        Command="{Binding StopGrabbingCommand}" />
+
+                        <TextBlock Text="{Binding Message}"
+           VerticalAlignment="Center"
+           Foreground="Gray" />
+                    </StackPanel>
+                </Grid>
+
+            </materialDesign:DrawerHost.LeftDrawerContent>
             <Grid>
             <Grid>
                 <Grid.ColumnDefinitions>
                 <Grid.ColumnDefinitions>
                     <ColumnDefinition Width="auto" />
                     <ColumnDefinition Width="auto" />
@@ -149,7 +205,7 @@
                                     <b:InvokeCommandAction Command="{Binding SelectionChangedCommand}" />
                                     <b:InvokeCommandAction Command="{Binding SelectionChangedCommand}" />
                                 </b:EventTrigger>
                                 </b:EventTrigger>
                             </b:Interaction.Triggers>
                             </b:Interaction.Triggers>
-                            <ListBoxItem>
+                            <ListBoxItem Visibility="Collapsed">
                                 <ListBoxItem.Style>
                                 <ListBoxItem.Style>
                                     <Style TargetType="ListBoxItem"
                                     <Style TargetType="ListBoxItem"
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
@@ -161,7 +217,7 @@
                                 </ListBoxItem.Style>
                                 </ListBoxItem.Style>
                                 <TextBlock Text="取料拍照点位" />
                                 <TextBlock Text="取料拍照点位" />
                             </ListBoxItem>
                             </ListBoxItem>
-                            <ListBoxItem>
+                            <ListBoxItem Visibility="Collapsed">
                                 <ListBoxItem.Style>
                                 <ListBoxItem.Style>
                                     <Style TargetType="ListBoxItem"
                                     <Style TargetType="ListBoxItem"
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
@@ -173,7 +229,7 @@
                                 </ListBoxItem.Style>
                                 </ListBoxItem.Style>
                                 <TextBlock Text="取料点位" />
                                 <TextBlock Text="取料点位" />
                             </ListBoxItem>
                             </ListBoxItem>
-                            <ListBoxItem>
+                            <ListBoxItem Visibility="Collapsed">
                                 <ListBoxItem.Style>
                                 <ListBoxItem.Style>
                                     <Style TargetType="ListBoxItem"
                                     <Style TargetType="ListBoxItem"
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
@@ -185,7 +241,7 @@
                                 </ListBoxItem.Style>
                                 </ListBoxItem.Style>
                                 <TextBlock Text="下相机二次定位点位" />
                                 <TextBlock Text="下相机二次定位点位" />
                             </ListBoxItem>
                             </ListBoxItem>
-                            <ListBoxItem>
+                            <ListBoxItem Visibility="Collapsed">
                                 <ListBoxItem.Style>
                                 <ListBoxItem.Style>
                                     <Style TargetType="ListBoxItem"
                                     <Style TargetType="ListBoxItem"
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
@@ -197,7 +253,7 @@
                                 </ListBoxItem.Style>
                                 </ListBoxItem.Style>
                                 <TextBlock Text="锁附拍照点位" />
                                 <TextBlock Text="锁附拍照点位" />
                             </ListBoxItem>
                             </ListBoxItem>
-                            <ListBoxItem>
+                            <ListBoxItem Visibility="Collapsed">
                                 <ListBoxItem.Style>
                                 <ListBoxItem.Style>
                                     <Style TargetType="ListBoxItem"
                                     <Style TargetType="ListBoxItem"
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
@@ -209,7 +265,7 @@
                                 </ListBoxItem.Style>
                                 </ListBoxItem.Style>
                                 <TextBlock Text="锁附点位" />
                                 <TextBlock Text="锁附点位" />
                             </ListBoxItem>
                             </ListBoxItem>
-                            <ListBoxItem>
+                            <ListBoxItem Visibility="Collapsed">
                                 <ListBoxItem.Style>
                                 <ListBoxItem.Style>
                                     <Style TargetType="ListBoxItem"
                                     <Style TargetType="ListBoxItem"
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
                                            BasedOn="{StaticResource MaterialDesign3.NavigationBarPrimaryListBoxItem}">
@@ -442,7 +498,7 @@
                                                            Text="X:" />
                                                            Text="X:" />
                                                 <mah:NumericUpDown Grid.Row="0"
                                                 <mah:NumericUpDown Grid.Row="0"
                                                                    Grid.Column="2"
                                                                    Grid.Column="2"
-                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos1.X_Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos1.X_Position_Start, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                                                    Minimum="-9999.000"
                                                                    Minimum="-9999.000"
                                                                    Maximum="9999.000"
                                                                    Maximum="9999.000"
                                                                    Interval="0.1"
                                                                    Interval="0.1"
@@ -459,7 +515,7 @@
                                                            Text="Y:" />
                                                            Text="Y:" />
                                                 <mah:NumericUpDown Grid.Row="0"
                                                 <mah:NumericUpDown Grid.Row="0"
                                                                    Grid.Column="4"
                                                                    Grid.Column="4"
-                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos1.Y_Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos1.Y_Position_Start, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                                                    Minimum="-9999.000"
                                                                    Minimum="-9999.000"
                                                                    Maximum="9999.000"
                                                                    Maximum="9999.000"
                                                                    Interval="0.1"
                                                                    Interval="0.1"
@@ -499,7 +555,7 @@
                                                            Text="X:" />
                                                            Text="X:" />
                                                 <mah:NumericUpDown Grid.Row="1"
                                                 <mah:NumericUpDown Grid.Row="1"
                                                                    Grid.Column="2"
                                                                    Grid.Column="2"
-                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos2.X_Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos2.X_Position_Start, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                                                    Minimum="-9999.000"
                                                                    Minimum="-9999.000"
                                                                    Maximum="9999.000"
                                                                    Maximum="9999.000"
                                                                    Interval="0.1"
                                                                    Interval="0.1"
@@ -516,7 +572,7 @@
                                                            Text="Y:" />
                                                            Text="Y:" />
                                                 <mah:NumericUpDown Grid.Row="1"
                                                 <mah:NumericUpDown Grid.Row="1"
                                                                    Grid.Column="4"
                                                                    Grid.Column="4"
-                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos2.Y_Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                                   Value="{Binding SelectProduct.ScrewCameraLocalPos2.Y_Position_Start, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                                                    Minimum="-9999.000"
                                                                    Minimum="-9999.000"
                                                                    Maximum="9999.000"
                                                                    Maximum="9999.000"
                                                                    Interval="0.1"
                                                                    Interval="0.1"
@@ -1435,7 +1491,31 @@
                                             </DataTemplate>
                                             </DataTemplate>
                                         </DataGridTemplateColumn.CellEditingTemplate>
                                         </DataGridTemplateColumn.CellEditingTemplate>
                                     </DataGridTemplateColumn>
                                     </DataGridTemplateColumn>
-
+                                    <!-- 对应的视觉流程选择 -->
+                                    <DataGridTemplateColumn Header="视觉流程"
+                                        MinWidth="150"
+                                        Width="Auto">
+                                        <DataGridTemplateColumn.CellTemplate>
+                                            <DataTemplate>
+                                                <!-- 显示已选流程名称(只读) -->
+                                                <ComboBox ItemsSource="{Binding DataContext.ProcedureModels, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
+                                                      SelectedValue="{Binding CameraProcedureId, Mode=OneWay}"
+                                                      SelectedValuePath="Id"
+                                                      DisplayMemberPath="Name"
+                                                      IsHitTestVisible="False"
+                                                      MinWidth="120" />
+                                            </DataTemplate>
+                                        </DataGridTemplateColumn.CellTemplate>
+                                        <DataGridTemplateColumn.CellEditingTemplate>
+                                            <DataTemplate>
+                                                <ComboBox ItemsSource="{Binding DataContext.ProcedureModels, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
+                                                      SelectedValue="{Binding CameraProcedureId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                      SelectedValuePath="Id"
+                                                      DisplayMemberPath="Name"
+                                                      MinWidth="120" />
+                                            </DataTemplate>
+                                        </DataGridTemplateColumn.CellEditingTemplate>
+                                    </DataGridTemplateColumn>
 
 
 
 
 
 
@@ -1462,6 +1542,15 @@
                                 <ColumnDefinition Width="auto" />
                                 <ColumnDefinition Width="auto" />
                                 <ColumnDefinition Width="auto" />
                                 <ColumnDefinition Width="auto" />
                             </Grid.ColumnDefinitions>
                             </Grid.ColumnDefinitions>
+                            <ToggleButton Grid.ColumnSpan="2"
+                                  HorizontalAlignment="Left"
+                                  VerticalAlignment="Top"
+                                  materialDesign:ToggleButtonAssist.OnContent="{materialDesign:PackIcon Kind=ArrowLeft}"
+                                  Content="{materialDesign:PackIcon Kind=Camera}"
+                                  Style="{StaticResource MaterialDesignActionToggleButton}"
+                                  ToolTip="相机图像"
+                                  Margin="5,0"
+                                  IsChecked="{Binding IsLeftDrawerOpen,ElementName=DrawerHost}" />
                             <Grid Grid.Column="0"
                             <Grid Grid.Column="0"
                                   VerticalAlignment="Center">
                                   VerticalAlignment="Center">
                                 <Grid.RowDefinitions>
                                 <Grid.RowDefinitions>

+ 74 - 1
TeamAAS-VM/Views/Product/PlcPointParams.xaml.cs

@@ -1,4 +1,8 @@
-using System.Windows.Controls;
+using Cognex.VisionPro;
+using Cognex.VisionPro.Dimensioning;
+using System;
+using System.Windows.Controls;
+using TeamAAS_VP.ViewModels.Product;
 
 
 namespace TeamAAS_VP.Views.Product
 namespace TeamAAS_VP.Views.Product
 {
 {
@@ -7,9 +11,78 @@ namespace TeamAAS_VP.Views.Product
     /// </summary>
     /// </summary>
     public partial class PlcPointParams : UserControl
     public partial class PlcPointParams : UserControl
     {
     {
+
+        PlcPointParamsViewModel VM;
         public PlcPointParams()
         public PlcPointParams()
         {
         {
             InitializeComponent();
             InitializeComponent();
+            VM = DataContext as PlcPointParamsViewModel;
+            VM.PropertyChanged += VM_PropertyChanged;
+            this.display.HorizontalScrollBar = false;
+            this.display.VerticalScrollBar = false;
+            this.display.AutoFit = true;
+            this.display.BackColor = System.Drawing.SystemColors.ActiveCaption;
+        }
+
+        private int _imageWidth;
+        private int _imageHeight;
+        private void VM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+        {
+            if (e.PropertyName == "Image")
+            {
+                if (this.display.Image == null)
+                {
+                    this.display.Image = VM.Image;
+                    //图像中心点坐标
+                    _imageWidth = this.display.Image.Width;
+                    _imageHeight = this.display.Image.Height;
+                    CogGraphicCollection graphic = new CogGraphicCollection();
+                    CogCreateLineTool line1 = new CogCreateLineTool();
+                    CogCreateLineTool line2 = new CogCreateLineTool();
+                    line1.InputImage = this.display.Image;
+                    line2.InputImage = this.display.Image;
+                    line1.Line.X = _imageWidth / 2;
+                    line1.Line.Y = _imageHeight / 2;
+                    line1.Line.Rotation = 0;
+                    line2.Line.X = _imageWidth / 2;
+                    line2.Line.Y = _imageHeight / 2;
+                    line2.Line.Rotation = Math.PI / 180 * 90;
+                    line1.Run();
+                    line2.Run();
+                    graphic.Add(line1.GetOutputLine());
+                    graphic.Add(line2.GetOutputLine());
+                    this.display.StaticGraphics.Clear();
+                    this.display.StaticGraphics.AddList(graphic, "");
+                }
+                else
+                {
+                    this.display.Image = VM.Image;
+                    //如果图像的长宽发生变化,则重新绘制十字线
+                    if (_imageWidth != this.display.Image.Width || _imageHeight != this.display.Image.Height)
+                    {
+                        _imageWidth = this.display.Image.Width;
+                        _imageHeight = this.display.Image.Height;
+                        CogGraphicCollection graphic = new CogGraphicCollection();
+                        CogCreateLineTool line1 = new CogCreateLineTool();
+                        CogCreateLineTool line2 = new CogCreateLineTool();
+                        line1.InputImage = this.display.Image;
+                        line2.InputImage = this.display.Image;
+                        line1.Line.X = _imageWidth / 2;
+                        line1.Line.Y = _imageHeight / 2;
+                        line1.Line.Rotation = 0;
+                        line2.Line.X = _imageWidth / 2;
+                        line2.Line.Y = _imageHeight / 2;
+                        line2.Line.Rotation = Math.PI / 180 * 90;
+                        line1.Run();
+                        line2.Run();
+                        graphic.Add(line1.GetOutputLine());
+                        graphic.Add(line2.GetOutputLine());
+                        this.display.StaticGraphics.Clear();
+                        this.display.StaticGraphics.AddList(graphic, "");
+                    }
+
+                }
+            }
         }
         }
     }
     }
 }
 }