新增CNC执行数据源的生成
This commit is contained in:
@@ -62,3 +62,4 @@ ExternalLibraries/Models/
|
|||||||
# 排除测试目录
|
# 排除测试目录
|
||||||
XplorePlane/Tests/
|
XplorePlane/Tests/
|
||||||
ExternalLibraries/Telerik/
|
ExternalLibraries/Telerik/
|
||||||
|
build_out.txt
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
using XP.Common.GeneralForm.Views;
|
using XP.Common.GeneralForm.Views;
|
||||||
using XP.Common.Logging.Interfaces;
|
using XP.Common.Logging.Interfaces;
|
||||||
using XplorePlane.Models;
|
using XplorePlane.Models;
|
||||||
using XplorePlane.Services.InspectionResults;
|
using XplorePlane.Services.InspectionResults;
|
||||||
|
using XplorePlane.Services.MainViewport;
|
||||||
|
using XplorePlane.ViewModels;
|
||||||
|
|
||||||
namespace XplorePlane.Services.Cnc
|
namespace XplorePlane.Services.Cnc
|
||||||
{
|
{
|
||||||
@@ -17,11 +22,22 @@ namespace XplorePlane.Services.Cnc
|
|||||||
{
|
{
|
||||||
private readonly IInspectionResultStore _store;
|
private readonly IInspectionResultStore _store;
|
||||||
private readonly ILoggerService _logger;
|
private readonly ILoggerService _logger;
|
||||||
|
private readonly IMainViewportService _mainViewportService;
|
||||||
|
private readonly IPipelineExecutionService _pipelineExecutionService;
|
||||||
|
private readonly IImageProcessingService _imageProcessingService;
|
||||||
|
|
||||||
public CncExecutionService(IInspectionResultStore store, ILoggerService logger)
|
public CncExecutionService(
|
||||||
|
IInspectionResultStore store,
|
||||||
|
ILoggerService logger,
|
||||||
|
IMainViewportService mainViewportService,
|
||||||
|
IPipelineExecutionService pipelineExecutionService,
|
||||||
|
IImageProcessingService imageProcessingService)
|
||||||
{
|
{
|
||||||
_store = store ?? throw new ArgumentNullException(nameof(store));
|
_store = store ?? throw new ArgumentNullException(nameof(store));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_mainViewportService = mainViewportService;
|
||||||
|
_pipelineExecutionService = pipelineExecutionService;
|
||||||
|
_imageProcessingService = imageProcessingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExecuteAsync(CncProgram program, IProgress<CncNodeExecutionProgress> progress, CancellationToken cancellationToken)
|
public async Task ExecuteAsync(CncProgram program, IProgress<CncNodeExecutionProgress> progress, CancellationToken cancellationToken)
|
||||||
@@ -32,6 +48,10 @@ namespace XplorePlane.Services.Cnc
|
|||||||
|
|
||||||
int inspectionNodeCount = program.Nodes.OfType<InspectionModuleNode>().Count();
|
int inspectionNodeCount = program.Nodes.OfType<InspectionModuleNode>().Count();
|
||||||
|
|
||||||
|
// 获取当前源图像(用于 run/source.bmp)
|
||||||
|
var sourceImage = _mainViewportService?.LatestManualImage as BitmapSource
|
||||||
|
?? _mainViewportService?.CurrentDisplayImage as BitmapSource;
|
||||||
|
|
||||||
Guid runId;
|
Guid runId;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -41,7 +61,21 @@ namespace XplorePlane.Services.Cnc
|
|||||||
NodeCount = inspectionNodeCount,
|
NodeCount = inspectionNodeCount,
|
||||||
StartedAt = DateTime.UtcNow
|
StartedAt = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
await _store.BeginRunAsync(runRecord);
|
|
||||||
|
InspectionAssetWriteRequest sourceAsset = null;
|
||||||
|
if (sourceImage != null)
|
||||||
|
{
|
||||||
|
sourceAsset = new InspectionAssetWriteRequest
|
||||||
|
{
|
||||||
|
AssetType = InspectionAssetType.RunSourceImage,
|
||||||
|
Content = EncodeBitmapToBmp(sourceImage),
|
||||||
|
FileFormat = "bmp",
|
||||||
|
Width = sourceImage.PixelWidth,
|
||||||
|
Height = sourceImage.PixelHeight
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await _store.BeginRunAsync(runRecord, sourceAsset);
|
||||||
runId = runRecord.RunId;
|
runId = runRecord.RunId;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -90,24 +124,7 @@ namespace XplorePlane.Services.Cnc
|
|||||||
case InspectionModuleNode inspectionNode:
|
case InspectionModuleNode inspectionNode:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var nodeResult = new InspectionNodeResult
|
await ExecuteInspectionNodeAsync(runId, inspectionNode, sourceImage, cancellationToken);
|
||||||
{
|
|
||||||
RunId = runId,
|
|
||||||
NodeId = inspectionNode.Id,
|
|
||||||
NodeIndex = inspectionNode.Index,
|
|
||||||
NodeName = inspectionNode.Name
|
|
||||||
};
|
|
||||||
|
|
||||||
PipelineExecutionSnapshot pipelineSnapshot = inspectionNode.Pipeline != null
|
|
||||||
? new PipelineExecutionSnapshot
|
|
||||||
{
|
|
||||||
RunId = runId,
|
|
||||||
NodeId = inspectionNode.Id,
|
|
||||||
PipelineName = inspectionNode.Pipeline.Name
|
|
||||||
}
|
|
||||||
: null;
|
|
||||||
|
|
||||||
await _store.AppendNodeResultAsync(nodeResult, pipelineSnapshot: pipelineSnapshot);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -162,6 +179,127 @@ namespace XplorePlane.Services.Cnc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteInspectionNodeAsync(
|
||||||
|
Guid runId,
|
||||||
|
InspectionModuleNode inspectionNode,
|
||||||
|
BitmapSource sourceImage,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var nodeResult = new InspectionNodeResult
|
||||||
|
{
|
||||||
|
RunId = runId,
|
||||||
|
NodeId = inspectionNode.Id,
|
||||||
|
NodeIndex = inspectionNode.Index,
|
||||||
|
NodeName = inspectionNode.Name,
|
||||||
|
PipelineName = inspectionNode.Pipeline?.Name ?? string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
PipelineExecutionSnapshot pipelineSnapshot = null;
|
||||||
|
if (inspectionNode.Pipeline != null)
|
||||||
|
{
|
||||||
|
var pipelineJson = JsonSerializer.Serialize(inspectionNode.Pipeline);
|
||||||
|
pipelineSnapshot = new PipelineExecutionSnapshot
|
||||||
|
{
|
||||||
|
RunId = runId,
|
||||||
|
NodeId = inspectionNode.Id,
|
||||||
|
PipelineName = inspectionNode.Pipeline.Name,
|
||||||
|
PipelineDefinitionJson = pipelineJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建资产列表
|
||||||
|
var assets = new System.Collections.Generic.List<InspectionAssetWriteRequest>();
|
||||||
|
|
||||||
|
// input.bmp — 当前源图像
|
||||||
|
if (sourceImage != null)
|
||||||
|
{
|
||||||
|
assets.Add(new InspectionAssetWriteRequest
|
||||||
|
{
|
||||||
|
AssetType = InspectionAssetType.NodeInputImage,
|
||||||
|
Content = EncodeBitmapToBmp(sourceImage),
|
||||||
|
FileFormat = "bmp",
|
||||||
|
Width = sourceImage.PixelWidth,
|
||||||
|
Height = sourceImage.PixelHeight
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// result_overlay.bmp — 执行流水线后的结果图像
|
||||||
|
if (_pipelineExecutionService != null && inspectionNode.Pipeline?.Nodes?.Count > 0 && sourceImage != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pipelineNodes = BuildPipelineNodeViewModels(inspectionNode.Pipeline);
|
||||||
|
var resultImage = await _pipelineExecutionService.ExecutePipelineAsync(
|
||||||
|
pipelineNodes, sourceImage, null, cancellationToken);
|
||||||
|
|
||||||
|
if (resultImage != null)
|
||||||
|
{
|
||||||
|
assets.Add(new InspectionAssetWriteRequest
|
||||||
|
{
|
||||||
|
AssetType = InspectionAssetType.NodeResultImage,
|
||||||
|
Content = EncodeBitmapToBmp(resultImage),
|
||||||
|
FileFormat = "bmp",
|
||||||
|
Width = resultImage.PixelWidth,
|
||||||
|
Height = resultImage.PixelHeight
|
||||||
|
});
|
||||||
|
nodeResult.Status = InspectionNodeStatus.Succeeded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ForModule<CncExecutionService>().Warn(
|
||||||
|
"Pipeline execution failed for node '{0}': {1}", inspectionNode.Name, ex.Message);
|
||||||
|
nodeResult.Status = InspectionNodeStatus.Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _store.AppendNodeResultAsync(nodeResult, pipelineSnapshot: pipelineSnapshot, assets: assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
private System.Collections.Generic.IEnumerable<ViewModels.PipelineNodeViewModel> BuildPipelineNodeViewModels(PipelineModel pipeline)
|
||||||
|
{
|
||||||
|
var nodes = new System.Collections.Generic.List<ViewModels.PipelineNodeViewModel>();
|
||||||
|
if (pipeline?.Nodes == null) return nodes;
|
||||||
|
|
||||||
|
foreach (var nodeModel in pipeline.Nodes.OrderBy(n => n.Order))
|
||||||
|
{
|
||||||
|
var displayName = _imageProcessingService?.GetProcessorDisplayName(nodeModel.OperatorKey) ?? nodeModel.OperatorKey;
|
||||||
|
var vm = new ViewModels.PipelineNodeViewModel(nodeModel.OperatorKey, displayName, string.Empty)
|
||||||
|
{
|
||||||
|
Order = nodeModel.Order,
|
||||||
|
IsEnabled = nodeModel.IsEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载参数定义并恢复保存的值
|
||||||
|
if (_imageProcessingService != null)
|
||||||
|
{
|
||||||
|
var paramDefs = _imageProcessingService.GetProcessorParameters(nodeModel.OperatorKey);
|
||||||
|
if (paramDefs != null)
|
||||||
|
{
|
||||||
|
foreach (var def in paramDefs)
|
||||||
|
{
|
||||||
|
var paramVm = new ViewModels.ProcessorParameterVM(def);
|
||||||
|
if (nodeModel.Parameters != null && nodeModel.Parameters.TryGetValue(def.Name, out var saved))
|
||||||
|
paramVm.Value = saved;
|
||||||
|
vm.Parameters.Add(paramVm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes.Add(vm);
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] EncodeBitmapToBmp(BitmapSource bitmap)
|
||||||
|
{
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
var encoder = new BmpBitmapEncoder();
|
||||||
|
encoder.Frames.Add(BitmapFrame.Create(bitmap));
|
||||||
|
encoder.Save(ms);
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task ExecuteWaitDelayWithProgressAsync(WaitDelayNode waitNode, CancellationToken cancellationToken)
|
private static async Task ExecuteWaitDelayWithProgressAsync(WaitDelayNode waitNode, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
int totalMs = waitNode.DelayMilliseconds;
|
int totalMs = waitNode.DelayMilliseconds;
|
||||||
|
|||||||
Reference in New Issue
Block a user