You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
16 KiB
526 lines
16 KiB
using System.Configuration; |
|
using System.Data; |
|
using System.IO; |
|
using System.Text; |
|
using System.Windows; |
|
using System.Windows.Input; |
|
using System.Windows.Media; |
|
using System.Windows.Media.Imaging; |
|
using Newtonsoft.Json; |
|
using Newtonsoft.Json.Linq; |
|
using SparkClient.Model.Common; |
|
using SparkClient.Model.Entity.ApiEntity; |
|
using SparkClient.Model.Helper; |
|
using SparkClient.Model.Services; |
|
using SparkClient.ViewModel.BaseWindow; |
|
using SparkClient.ViewModel.Configuration; |
|
using SparkClient.Views.Dialog; |
|
using SparkDotNetCore.DiamondScanner; |
|
using SparkDotNetCore.DiamondScanner.Entity; |
|
using MessageBox = SparkClient.Views.Dialog.MessageBox; |
|
|
|
namespace SparkClient.ViewModel.Grading; |
|
|
|
public class GradingLoadingVM : BaseViewModel,IDisposable |
|
{ |
|
private double _progress; |
|
private SOCClientService _socClientService; |
|
public AlgorithmResultEntity Parameter; |
|
/// <summary> |
|
/// 进度 |
|
/// </summary> |
|
public double Progress |
|
{ |
|
get => _progress; |
|
set |
|
{ |
|
_progress = value; |
|
OnPropertyChanged(nameof(Progress)); |
|
} |
|
} |
|
|
|
|
|
public ICommand StopCommand { get; } |
|
|
|
private string _diamondCode; |
|
|
|
private string _diamnondType; |
|
|
|
private bool _disposed; |
|
|
|
private CancellationTokenSource _progressCts; |
|
private CancellationTokenSource? _playbackCts; |
|
private Diamond _diamond; |
|
private Scanner _scanner; |
|
private CancellationTokenSource _completionCts; |
|
|
|
#region 图片播放控制 |
|
private PlayStatus _currentStatus = PlayStatus.Stopped; |
|
public PlayStatus CurrentStatus |
|
{ |
|
get => _currentStatus; |
|
set |
|
{ |
|
_currentStatus = value; |
|
OnPropertyChanged(nameof(CurrentStatus)); |
|
OnPropertyChanged(nameof(ButtonText)); // 状态变更时更新按钮文本 |
|
} |
|
} |
|
public string ButtonText => CurrentStatus switch |
|
{ |
|
PlayStatus.Playing => MultilingualHelper.getString("GradingLoadingPaused"), |
|
PlayStatus.Paused => MultilingualHelper.getString("GradingLoadingContinue"), |
|
_ => MultilingualHelper.getString("GradingLoadingReplay") // Stopped 状态 |
|
}; |
|
private CancellationTokenSource _cts; |
|
private int _playDelay = 100; // 默认播放速度 |
|
|
|
public ICommand PlayControlCommand { get; } |
|
public ICommand PreviousCommand { get; } |
|
public ICommand NextCommand { get; } |
|
|
|
private int _currentIndex; |
|
public int CurrentIndex |
|
{ |
|
get => _currentIndex; |
|
set |
|
{ |
|
_currentIndex = value; |
|
OnPropertyChanged(nameof(CurrentIndex)); |
|
UpdateCurrentImage(); |
|
} |
|
} |
|
|
|
public string[] ImagePaths { get; set; } |
|
private ImageSource _currentImage; |
|
public ImageSource CurrentImage |
|
{ |
|
get => _currentImage; |
|
private set |
|
{ |
|
_currentImage = value; |
|
OnPropertyChanged(nameof(CurrentImage)); |
|
} |
|
} |
|
|
|
private bool _imageIsEnable; |
|
public bool ImageIsEnable |
|
{ |
|
get => _imageIsEnable; |
|
private set |
|
{ |
|
_imageIsEnable = value; |
|
OnPropertyChanged(nameof(ImageIsEnable)); // 触发通知 |
|
} |
|
} |
|
#endregion |
|
|
|
public GradingLoadingVM(string diamnondType, string diamondCode) |
|
{ |
|
_diamondCode = diamondCode; |
|
_diamnondType = diamnondType; |
|
StopCommand = new RelayCommand(Stop); |
|
PlayControlCommand = new RelayCommand(async _ => await HandlePlayControl()); |
|
PreviousCommand = new RelayCommand(_ => MovePrevious()); |
|
NextCommand = new RelayCommand(_ => MoveNext()); |
|
ImageIsEnable = false; |
|
|
|
_progressCts = new CancellationTokenSource(); |
|
_playbackCts = new CancellationTokenSource(); |
|
_completionCts = new CancellationTokenSource(); |
|
} |
|
|
|
/// <summary> |
|
/// 开始检测 |
|
/// </summary> |
|
public async Task<int> Start(int type = 0) |
|
{ |
|
|
|
try |
|
{ |
|
|
|
var progress = RunProgressAsync(_progressCts.Token); |
|
|
|
if (type == 11) |
|
{ |
|
JsonImport jsonImport = new JsonImport(); |
|
bool? a = jsonImport.ShowDialog(); |
|
if (a ?? false) |
|
{ |
|
string fileName = jsonImport.FilePath.Text; |
|
string[] lines = File.ReadAllLines(fileName); |
|
StringBuilder stringBuilder = new StringBuilder(); |
|
|
|
foreach (var line in lines) |
|
{ |
|
stringBuilder.Append(line); |
|
} |
|
Parameter = JsonConvert.DeserializeObject<AlgorithmResultEntity>(stringBuilder.ToString()); |
|
await CompleteProgressQuicklyAsync(); |
|
return 0; |
|
} |
|
else |
|
{ |
|
return -1; |
|
} |
|
} |
|
|
|
if(type == 0){ |
|
_socClientService = new SOCClientService(); |
|
var processImage = _socClientService.ProcessImageCollectionAsync(); |
|
//通知页面可以播放图片 |
|
await processImage; |
|
|
|
if (!("ok".Equals(processImage.Result.Status) || "S000".Equals(processImage.Result.Status))) |
|
{ |
|
_progressCts.Cancel(); |
|
new MessageBox().Show( |
|
MultilingualHelper.getString(StatusCodes.GetConstantNameByValue(processImage.Result.Status))); |
|
return -1; |
|
} |
|
LoadImages(processImage.Result.Images); |
|
} |
|
|
|
if (type == 1) |
|
{ |
|
List<string> mnFiles = new List<string>(); |
|
for (int i = 0; i < 100; i++) |
|
{ |
|
mnFiles.Add($"{i}.bmp"); |
|
} |
|
LoadImages(mnFiles); |
|
} |
|
|
|
ImageIsEnable = true; |
|
StartPlayback(); |
|
|
|
|
|
Diamond diamond = new Diamond(); |
|
string circleSql = $"SELECT VALUE FROM CUTTER_CONFIG WHERE KEY = 'half_circle'"; |
|
DataTable circleTable = DataBaseHelper.ExecuteQuery(circleSql); |
|
object halfCircleValue = circleTable.Rows[0][0]; |
|
bool.TryParse(halfCircleValue.ToString(), out bool boolResult); |
|
bool half_circle = boolResult; |
|
|
|
//算法配置参数,初始化算法配置数据并获取 AlgorithmConfigJson |
|
var _algorithmConfigVM = new AlgorithmConfigVM(); |
|
_algorithmConfigVM.InitAlgorithmData(null); |
|
string algo_config = _algorithmConfigVM.AlgorithmConfigJson; |
|
|
|
|
|
//图片根目录 |
|
string? image_file_base_path = ConfigurationManager.AppSettings["ImageFileBasePath"]; |
|
if (string.IsNullOrEmpty(image_file_base_path)) |
|
{ |
|
throw new InvalidOperationException("ImageFileBasePath is not configured in AppSettings."); |
|
} |
|
|
|
// 获取 log4net 日志文件所在的目录 |
|
string? log4NetLogDirectory = |
|
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); |
|
// 构建C++ DLL 日志文件路径 |
|
string algorithm_log_path = Path.Combine(log4NetLogDirectory, "logs"); |
|
|
|
// 将所有变量拼接成一个 JSON 对象 |
|
JObject jsonData = new JObject( |
|
new JProperty("shape", _diamnondType.Split(" ")[0]), |
|
new JProperty("shape_mode", _diamnondType.Split(" ")[1]), |
|
new JProperty("image_file_base_path", image_file_base_path), |
|
new JProperty("image_files", ImagePaths), |
|
new JProperty("half_circle", half_circle), |
|
new JProperty("algorithm_log_path", algorithm_log_path), |
|
new JProperty("algo_config", JObject.Parse(algo_config)) |
|
); |
|
_scanner = new Scanner(diamond); |
|
var detectTask = _scanner.DetectAsyncByJsonStr(jsonData.ToString()); |
|
|
|
await detectTask; |
|
if (detectTask.Status == TaskStatus.RanToCompletion) |
|
{ |
|
return ReslutGen(detectTask); |
|
} |
|
await progress; |
|
return ReslutGen(detectTask); |
|
} |
|
catch(Exception ex) |
|
{ |
|
return -100; |
|
} |
|
} |
|
|
|
private int ReslutGen(Task<DiaResult> detectTask) |
|
{ |
|
|
|
CompleteProgressQuicklyAsync(); |
|
|
|
|
|
switch (detectTask.Result.Status) |
|
{ |
|
case StatusCodes.AlgorithmFailed: |
|
new MessageBox().Show(MultilingualHelper.getString("AlgorithmFailed")); |
|
return -1; |
|
case StatusCodes.ImageFileReadFailure: |
|
new MessageBox().Show(MultilingualHelper.getString("ImageFileReadFailure")); |
|
return -1; |
|
case StatusCodes.JsonParseFailure: |
|
new MessageBox().Show(MultilingualHelper.getString("JsonParseFailure")); |
|
return -1; |
|
case StatusCodes.NoDiamond: |
|
new MessageBox().Show(MultilingualHelper.getString("NoDiamond")); |
|
return -1; |
|
} |
|
|
|
Progress = 100; |
|
|
|
string strParam = JsonConvert.SerializeObject(detectTask.Result); |
|
AlgorithmResultEntity parameter = JsonConvert.DeserializeObject<AlgorithmResultEntity>(strParam); |
|
if (parameter == null) |
|
{ |
|
new MessageBox().Show(MultilingualHelper.getString("JsonParseFailure")); |
|
return -1; |
|
} |
|
|
|
try |
|
{ |
|
string parameterJson = JsonConvert.SerializeObject(parameter); |
|
parameterJson = JToken.Parse(parameterJson).ToString(); |
|
string outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "result"); |
|
if (!Directory.Exists(outputPath)) |
|
Directory.CreateDirectory(outputPath); |
|
string outputFilePath = $"{outputPath}/{_diamondCode}-{DateTime.Now:yyyyMMdd_HHmmss}.json"; |
|
using (var file = File.Create(outputFilePath)) |
|
using (StreamWriter stream = new StreamWriter(file)) |
|
{ |
|
stream.Write(parameterJson); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Logger.Error("output输出失败:" + ex.Message); |
|
} |
|
|
|
Parameter = parameter; |
|
return 0; |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
private async Task CompleteProgressQuicklyAsync() |
|
{ |
|
// 取消原进度任务 |
|
_progressCts.Cancel(); |
|
|
|
// 快速完成剩余进度(0.5秒内完成) |
|
int current = (int)Progress; |
|
int remaining = 100 - current; |
|
if (remaining <= 0) return; |
|
|
|
int stepTime = Math.Max(50, 500 / remaining); // 动态计算步长 |
|
|
|
while (current < 100) |
|
{ |
|
current = Math.Min(current + 1, 100); |
|
UpdateProgress(current); |
|
await Task.Delay(stepTime); |
|
} |
|
} |
|
private void UpdateProgress(int value) |
|
{ |
|
// UI线程安全更新 |
|
Application.Current.Dispatcher.Invoke(() => |
|
{ |
|
Progress = value; |
|
}); |
|
} |
|
private void Stop(object param) |
|
{ |
|
//询问?停止:忽略 |
|
try |
|
{ |
|
MessageBox messageBox = new MessageBox(); |
|
MessageBoxResult showAsk = messageBox.ShowAsk(MultilingualHelper.getString("GradingLoadingStopAsk")); |
|
if (showAsk == MessageBoxResult.OK) |
|
{ |
|
WindowManager.mainViewModel.Content = WindowManager.PreviousVM(); |
|
_scanner?.Cancel(); |
|
_progressCts.Cancel(); |
|
this.Dispose(); |
|
} |
|
|
|
} |
|
catch (Exception ex) |
|
{ |
|
|
|
} |
|
|
|
} |
|
|
|
private async Task RunProgressAsync(CancellationToken token) |
|
{ |
|
var configValue = ConfigurationHelper.ReadConfigValue("ProgressTime"); |
|
int totalDuration = int.TryParse(configValue, out var result) ? result : 50000; |
|
int stepTime = totalDuration / 97; |
|
|
|
// 使用 IProgress 实现线程安全的进度报告 |
|
var progress = new Progress<double>(value => |
|
{ |
|
if (!token.IsCancellationRequested) |
|
Progress = value; |
|
}); |
|
|
|
await Task.Run(async () => |
|
{ |
|
for (int i = 0; i <= 97; i++) |
|
{ |
|
token.ThrowIfCancellationRequested(); |
|
|
|
// 报告进度 |
|
((IProgress<double>)progress).Report(i); |
|
|
|
// 使用可取消的延迟 |
|
await Task.Delay(stepTime, token); |
|
} |
|
}, token); |
|
} |
|
|
|
|
|
public void Dispose() |
|
{ |
|
Dispose(true); |
|
GC.SuppressFinalize(this); |
|
} |
|
|
|
protected virtual void Dispose(bool disposing) |
|
{ |
|
if (_disposed) return; |
|
|
|
if (disposing) |
|
{ |
|
// 取消所有操作 |
|
_progressCts?.Cancel(); |
|
_playbackCts?.Cancel(); |
|
|
|
// 释放托管资源 |
|
_progressCts?.Dispose(); |
|
_playbackCts?.Dispose(); |
|
} |
|
|
|
_disposed = true; |
|
} |
|
|
|
#region 图片播放处理 |
|
|
|
public void LoadImages(string folderPath) |
|
{ |
|
ImagePaths = Directory.GetFiles(folderPath, "*.bmp"); |
|
CurrentIndex = 0; |
|
CurrentStatus = PlayStatus.Stopped; |
|
} |
|
public void LoadImages(List<string> folderPath) |
|
{ |
|
ImagePaths = folderPath.ToArray(); |
|
CurrentIndex = 0; |
|
CurrentStatus = PlayStatus.Stopped; |
|
} |
|
private async Task HandlePlayControl() |
|
{ |
|
switch (CurrentStatus) |
|
{ |
|
case PlayStatus.Stopped: |
|
await StartPlayback(); // 开始或重播 |
|
break; |
|
case PlayStatus.Playing: |
|
PausePlayback(); // 暂停 |
|
break; |
|
case PlayStatus.Paused: |
|
await ResumePlayback();// 继续 |
|
break; |
|
} |
|
} |
|
private async Task StartPlayback() |
|
{ |
|
CurrentStatus = PlayStatus.Playing; |
|
_cts = new CancellationTokenSource(); |
|
|
|
try |
|
{ |
|
for (CurrentIndex = 0; CurrentIndex < ImagePaths.Length; CurrentIndex++) |
|
{ |
|
if (_cts.Token.IsCancellationRequested) break; |
|
await Task.Delay(_playDelay); |
|
} |
|
|
|
// 播放完成处理 |
|
if (CurrentIndex >= ImagePaths.Length) |
|
{ |
|
CurrentStatus = PlayStatus.Stopped; |
|
CurrentIndex = 0; // 重置为初始位置 |
|
} |
|
} |
|
catch (TaskCanceledException) { /* 正常取消处理 */ } |
|
} |
|
|
|
private void PausePlayback() |
|
{ |
|
_cts?.Cancel(); |
|
CurrentStatus = PlayStatus.Paused; |
|
} |
|
|
|
private async Task ResumePlayback() |
|
{ |
|
CurrentStatus = PlayStatus.Playing; |
|
_cts = new CancellationTokenSource(); |
|
await StartPlayback(); |
|
} |
|
private void UpdateCurrentImage() |
|
{ |
|
if (ImagePaths == null || CurrentIndex < 0 || CurrentIndex >= ImagePaths.Length) |
|
return; |
|
string? savePath = ConfigurationManager.AppSettings["ImageFileBasePath"]; |
|
var bitmap = new BitmapImage(); |
|
bitmap.BeginInit(); |
|
bitmap.CacheOption = BitmapCacheOption.OnLoad; |
|
bitmap.UriSource = new Uri(savePath + @"\" + ImagePaths[CurrentIndex]); |
|
bitmap.EndInit(); |
|
bitmap.Freeze(); // 确保跨线程安全# |
|
|
|
CurrentImage = bitmap; |
|
OnPropertyChanged(nameof(CurrentImage)); |
|
} |
|
|
|
private void MovePrevious() |
|
{ |
|
if (CurrentStatus == PlayStatus.Playing) |
|
PausePlayback(); |
|
|
|
CurrentIndex = (CurrentIndex - 1 + ImagePaths.Length) % ImagePaths.Length; |
|
} |
|
|
|
private void MoveNext() |
|
{ |
|
if (CurrentStatus == PlayStatus.Playing) |
|
PausePlayback(); |
|
|
|
CurrentIndex = (CurrentIndex + 1) % ImagePaths.Length; |
|
} |
|
#endregion |
|
} |
|
public enum PlayStatus |
|
{ |
|
Stopped, // 初始/停止状态 |
|
Playing, // 播放中 |
|
Paused // 暂停中 |
|
} |