using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using System.Windows; using DrillTools.Integration; namespace DrillTools { /// /// 主窗口视图模型 /// public class MainWindowViewModel : INotifyPropertyChanged { private ObservableCollection _tools = new(); private ToolItem? _selectedTool; private string _drillTapeContent = string.Empty; private bool _canMoveUp; private bool _canMoveDown; private string _originalFilePath = string.Empty; /// /// 刀具列表 /// public ObservableCollection Tools { get => _tools; set => SetProperty(ref _tools, value); } /// /// 选中的刀具 /// public ToolItem? SelectedTool { get => _selectedTool; set { if (SetProperty(ref _selectedTool, value)) { UpdateMoveButtonsState(); } } } /// /// 钻带内容 /// public string DrillTapeContent { get => _drillTapeContent; set => SetProperty(ref _drillTapeContent, value); } /// /// 是否可以上移 /// public bool CanMoveUp { get => _canMoveUp; set => SetProperty(ref _canMoveUp, value); } /// /// 是否可以下移 /// public bool CanMoveDown { get => _canMoveDown; set => SetProperty(ref _canMoveDown, value); } /// /// 原始文件路径 /// public string OriginalFilePath { get => _originalFilePath; set { if (SetProperty(ref _originalFilePath, value)) { // 当原始文件路径改变时,通知 HasOriginalFile 属性也已更改 OnPropertyChanged(nameof(HasOriginalFile)); } } } /// /// 是否有原始文件 /// public bool HasOriginalFile => !string.IsNullOrEmpty(OriginalFilePath); /// /// 从钻带内容加载刀具信息 /// /// 钻带内容 public void LoadToolsFromDrillTape(string drillTapeContent) { DrillTapeContent = drillTapeContent; Tools.Clear(); try { // 使用现有的 DrillTapeProcessor 处理钻带数据 var result = DrillTapeProcessor.ProcessDrillTape(drillTapeContent); if (result.Success) { foreach (var toolResult in result.ToolResults) { var toolItem = new ToolItem { ToolNumber = toolResult.ToolNumber, Diameter = toolResult.Diameter, // 孔数相关属性已移除 // RegularHoles = toolResult.RegularHoles; // SlotHoles = toolResult.SlotHoles; // TotalHoles = toolResult.TotalHoles; ToolType = toolResult.ToolType, ToolSuffixType = toolResult.ToolSuffixType, ToolCategory = toolResult.ToolCategory, HoleLocations = toolResult.Locations ?? new List() }; // 如果是机台码,使用DrillTapeProcessor已经解析出的机台码信息 if (toolResult.ToolType == ToolType.MachineCode) { toolItem.MachineCodeCommand = toolResult.MachineCodeCommand; toolItem.MachineCodeType = toolResult.MachineCodeType; // 添加日志验证机台码信息传递 System.Diagnostics.Debug.WriteLine($"[机台码传递] T{toolResult.ToolNumber:D2}: 命令={toolItem.MachineCodeCommand}, 类型={toolItem.MachineCodeType}"); // 如果 toolResult.Locations 已经包含坐标数据,则使用它 // 否则从原始钻带内容中提取坐标行 if (toolItem.HoleLocations == null || toolItem.HoleLocations.Count == 0) { // 从钻带内容中提取机台码坐标行 var toolPattern = $@"%.+?T{toolResult.ToolNumber:D2}(.*?)(?=T\d{{2}}|M30)"; var match = System.Text.RegularExpressions.Regex.Match(DrillTapeContent, toolPattern, System.Text.RegularExpressions.RegexOptions.Singleline); if (match.Success) { string holeSection = match.Groups[1].Value; // 查找机台码坐标行 var coordinatePattern = @"X([+-]?\d+\.?\d*)Y([+-]?\d+\.?\d*)"; var coordinateMatches = System.Text.RegularExpressions.Regex.Matches(holeSection, coordinatePattern); toolItem.HoleLocations = new List(); foreach (Match coordMatch in coordinateMatches) { toolItem.HoleLocations.Add(coordMatch.Value); } System.Diagnostics.Debug.WriteLine($"[机台码坐标] T{toolResult.ToolNumber:D2}: 找到{toolItem.HoleLocations.Count}个坐标"); } } } Tools.Add(toolItem); } // 更新按钮状态 UpdateMoveButtonsState(); } else { System.Windows.MessageBox.Show($"解析钻带失败: {result.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } catch (Exception ex) { System.Windows.MessageBox.Show($"解析钻带时发生异常: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } /// /// 重新排序刀具 /// /// 原索引 /// 新索引 public void ReorderTools(int oldIndex, int newIndex) { if (oldIndex < 0 || oldIndex >= Tools.Count || newIndex < 0 || newIndex >= Tools.Count) return; var tool = Tools[oldIndex]; // 检查是否是机台码刀具,如果是则不允许移动 if (tool.ToolType == ToolType.MachineCode) { System.Windows.MessageBox.Show("机台码刀具不允许移动位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } // 检查目标位置是否是机台码刀具 var targetTool = Tools[newIndex]; if (targetTool.ToolType == ToolType.MachineCode) { System.Windows.MessageBox.Show("不能移动到机台码刀具位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } Tools.RemoveAt(oldIndex); Tools.Insert(newIndex, tool); } /// /// 上移选中的刀具 /// public void MoveSelectedToolUp() { if (SelectedTool == null || !CanMoveUp) return; int currentIndex = Tools.IndexOf(SelectedTool); System.Diagnostics.Debug.WriteLine($"[MoveUp] 开始上移操作,选中项索引: {currentIndex}, 刀具编号: T{SelectedTool.ToolNumber:D2}"); if (currentIndex > 0) { // 检查是否是机台码刀具 if (SelectedTool.ToolType == ToolType.MachineCode) { System.Windows.MessageBox.Show("机台码刀具不允许移动位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } // 检查目标位置是否是机台码刀具 var targetTool = Tools[currentIndex - 1]; if (targetTool.ToolType == ToolType.MachineCode) { System.Windows.MessageBox.Show("不能移动到机台码刀具位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } // 保存选中的刀具引用 var selectedTool = SelectedTool; int newIndex = currentIndex - 1; // 执行上移操作 Tools.RemoveAt(currentIndex); Tools.Insert(newIndex, selectedTool); System.Diagnostics.Debug.WriteLine($"[MoveUp] 上移完成,新索引: {newIndex}"); // 使用延迟方法重新选中移动后的项 System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { System.Diagnostics.Debug.WriteLine($"[MoveUp] 延迟设置选中项,刀具编号: T{selectedTool.ToolNumber:D2}"); SelectedTool = selectedTool; UpdateMoveButtonsState(); }), System.Windows.Threading.DispatcherPriority.Background); } } /// /// 下移选中的刀具 /// public void MoveSelectedToolDown() { if (SelectedTool == null || !CanMoveDown) return; int currentIndex = Tools.IndexOf(SelectedTool); System.Diagnostics.Debug.WriteLine($"[MoveDown] 开始下移操作,选中项索引: {currentIndex}, 刀具编号: T{SelectedTool.ToolNumber:D2}"); if (currentIndex >= 0 && currentIndex < Tools.Count - 1) { // 检查是否是机台码刀具 if (SelectedTool.ToolType == ToolType.MachineCode) { System.Windows.MessageBox.Show("机台码刀具不允许移动位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } // 检查目标位置是否是机台码刀具 var targetTool = Tools[currentIndex + 1]; if (targetTool.ToolType == ToolType.MachineCode) { System.Windows.MessageBox.Show("不能移动到机台码刀具位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } // 保存选中的刀具引用 var selectedTool = SelectedTool; int newIndex = currentIndex + 1; // 执行下移操作 Tools.RemoveAt(currentIndex); Tools.Insert(newIndex, selectedTool); System.Diagnostics.Debug.WriteLine($"[MoveDown] 下移完成,新索引: {newIndex}"); // 使用延迟方法重新选中移动后的项 System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { System.Diagnostics.Debug.WriteLine($"[MoveDown] 延迟设置选中项,刀具编号: T{selectedTool.ToolNumber:D2}"); SelectedTool = selectedTool; UpdateMoveButtonsState(); }), System.Windows.Threading.DispatcherPriority.Background); } } /// /// 更新上移/下移按钮的状态 /// private void UpdateMoveButtonsState() { if (SelectedTool == null) { CanMoveUp = false; CanMoveDown = false; System.Diagnostics.Debug.WriteLine("[UpdateButtons] 没有选中项,禁用所有按钮"); return; } int index = Tools.IndexOf(SelectedTool); CanMoveUp = index > 0; CanMoveDown = index >= 0 && index < Tools.Count - 1; System.Diagnostics.Debug.WriteLine($"[UpdateButtons] 选中项索引: {index}, CanMoveUp: {CanMoveUp}, CanMoveDown: {CanMoveDown}"); } /// /// 保存刀具顺序并应用到钻带处理 /// /// 重新排序后的钻带内容 public string ApplyToolOrderToDrillTape() { if (string.IsNullOrEmpty(OriginalFilePath)) { throw new InvalidOperationException("没有原始文件路径,请先加载钻带文件"); } if (Tools.Count == 0) { throw new InvalidOperationException("没有刀具数据,请先加载钻带文件"); } try { // 1. 使用现有的扩展方法生成重新排序后的钻带内容 string reorderedDrillTape = DrillTapeProcessorExtensions.GenerateReorderedDrillTape(DrillTapeContent, Tools.ToList()); // 2. 改进的备份逻辑 if (File.Exists(OriginalFilePath)) { string backupFilePath = OriginalFilePath + ".bak"; // 检查备份文件是否已存在 if (File.Exists(backupFilePath)) { var result = System.Windows.MessageBox.Show( "备份文件已存在,请选择处理方式:\n\n" + "是(Y):覆盖现有备份文件\n" + "否(N):创建带时间戳的新备份文件\n" + "取消:中止保存操作\n\n" + "提示:选择'否'可以保留之前的备份历史", "备份选项", MessageBoxButton.YesNoCancel, MessageBoxImage.Question); switch (result) { case MessageBoxResult.Yes: // 覆盖现有备份文件 File.Copy(OriginalFilePath, backupFilePath, true); break; case MessageBoxResult.No: // 创建带时间戳的新备份文件 string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); string timestampBackupPath = $"{OriginalFilePath}.{timestamp}.bak"; File.Copy(OriginalFilePath, timestampBackupPath); break; case MessageBoxResult.Cancel: // 用户取消操作 throw new OperationCanceledException("用户取消了保存操作"); } } else { // 备份文件不存在,直接创建 File.Copy(OriginalFilePath, backupFilePath); } } // 3. 将重新排序后的钻带内容写入原始文件 File.WriteAllText(OriginalFilePath, reorderedDrillTape); // 4. 更新当前钻带内容 DrillTapeContent = reorderedDrillTape; return reorderedDrillTape; } catch (OperationCanceledException) { // 重新抛出取消异常,不包装 throw; } catch (Exception ex) { throw new InvalidOperationException($"保存钻带文件失败: {ex.Message}", ex); } } /// /// 重排刀序并重新编号 /// /// 重排后的钻带内容 public string ReorderAndRenumberTools() { if (Tools.Count == 0) { throw new InvalidOperationException("没有可重排的刀具"); } // 1. 创建原始刀具编号到新编号的映射 var toolNumberMapping = new Dictionary(); var originalToNewMapping = new Dictionary(); // 保存原始映射关系 // 2. 按当前列表顺序重新编号(T01, T02, T03...) int newToolNumber = 1; foreach (var tool in Tools.ToList()) { // 机台码刀具不允许重新编号 if (tool.ToolType != ToolType.MachineCode) { originalToNewMapping[tool.ToolNumber] = newToolNumber; toolNumberMapping[tool.ToolNumber] = newToolNumber; tool.ToolNumber = newToolNumber++; } else { // 机台码刀具保持原始编号,但也要加入映射 toolNumberMapping[tool.ToolNumber] = tool.ToolNumber; } } // 3. 更新钻带内容中的刀具编号和孔位数据 string updatedDrillTape = UpdateDrillTapeWithNewToolNumbers(DrillTapeContent, toolNumberMapping); // 4. 更新钻带内容 DrillTapeContent = updatedDrillTape; // 5. 更新界面显示 OnPropertyChanged(nameof(Tools)); return updatedDrillTape; } /// /// 使用新的刀具编号更新钻带内容 /// /// 原始钻带内容 /// 刀具编号映射 /// 更新后的钻带内容 private string UpdateDrillTapeWithNewToolNumbers(string originalDrillTape, Dictionary toolNumberMapping) { var lines = originalDrillTape.Split(new[] { '\r', '\n' }, StringSplitOptions.None); var result = new List(); // 创建新编号到刀具对象的映射,以便获取对应的坐标数据 var newNumberToToolMap = new Dictionary(); foreach (var tool in Tools) { if (toolNumberMapping.ContainsValue(tool.ToolNumber)) { newNumberToToolMap[tool.ToolNumber] = tool; } } // 首先解析原始钻带中的刀具定义行,保存参数信息 var originalToolDefinitions = new Dictionary(); var headerLines = new List(); foreach (var line in lines) { string trimmedLine = line.Trim(); if (trimmedLine == "%") { //headerLines.Add(line); break; } // 处理刀具定义行(如 T01C1.049H05000Z+0.000S060.00F105.0U0700.0) if (Regex.IsMatch(trimmedLine, @"^T(\d+)C")) { var match = Regex.Match(trimmedLine, @"^T(\d+)C(.*)$"); if (match.Success) { int originalToolNumber = int.Parse(match.Groups[1].Value); originalToolDefinitions[originalToolNumber] = match.Groups[2].Value; } } else { if (line != "") headerLines.Add(line); } } // 添加头部信息 result.AddRange(headerLines); // 按照新的刀具编号顺序输出刀具定义部分 var sortedTools = Tools.OrderBy(t => t.ToolNumber).ToList(); foreach (var tool in sortedTools) { // 查找原始刀具编号 int originalToolNumber = -1; foreach (var kvp in toolNumberMapping) { if (kvp.Value == tool.ToolNumber) { originalToolNumber = kvp.Key; break; } } if (originalToolNumber != -1 && originalToolDefinitions.ContainsKey(originalToolNumber)) { string toolDef = $"T{tool.ToolNumber:D2}C{originalToolDefinitions[originalToolNumber]}"; result.Add(toolDef); } } // 添加 % 符号 result.Add("%"); // 处理刀具切换行和坐标数据部分 // 按新刀具编号顺序输出刀具切换行和对应的坐标数据 var sortedToolsForData = Tools.OrderBy(t => t.ToolNumber).ToList(); foreach (var tool in sortedToolsForData) { // 添加刀具切换行 result.Add($"T{tool.ToolNumber:D2}"); // 添加该刀具对应的所有坐标数据 if (tool.ToolType != ToolType.MachineCode && tool.HoleLocations != null && tool.HoleLocations.Count > 0) { foreach (var location in tool.HoleLocations) { result.Add(location); } } // 如果是机台码刀具,添加机台码命令和坐标 if (tool.ToolType == ToolType.MachineCode) { if (!string.IsNullOrEmpty(tool.MachineCodeCommand) && !string.IsNullOrEmpty(tool.MachineCodeType)) { result.Add($"{tool.MachineCodeCommand},{tool.MachineCodeType},$S $N"); // 添加机台码的坐标数据 if (tool.HoleLocations != null && tool.HoleLocations.Count > 0) { foreach (var location in tool.HoleLocations) { result.Add(location); } } } } } // 添加结束标记 result.Add("M30"); return string.Join("\r\n", result); } /// /// 加载示例数据 /// public void LoadSampleData() { // 清空原始文件路径,因为这是示例数据 OriginalFilePath = string.Empty; Tools.Clear(); // 添加示例刀具数据 Tools.Add(new ToolItem { ToolNumber = 1, Diameter = 1.049, // 尾号9,特殊孔径固定为圆孔 // 孔数相关属性已移除 // RegularHoles = 7, // SlotHoles = 0, // TotalHoles = 7, ToolType = ToolType.Regular, ToolSuffixType = ToolItem.GetToolSuffixType(1.049), // 特殊孔径 ToolCategory = ToolItem.GetToolCategory(ToolItem.GetToolSuffixType(1.049)), HoleLocations = new List { "X-167525Y013500", "X-167525Y018500", "X-167525Y023500", "X167525Y013500", "X167525Y018500", "X167525Y023500", "X099366Y502000" } }); Tools.Add(new ToolItem { ToolNumber = 2, Diameter = 1.550, // 尾号0 -> 钻针 // 孔数相关属性已移除 // RegularHoles = 5, // SlotHoles = 0, // TotalHoles = 5, ToolType = ToolType.Regular, ToolSuffixType = ToolItem.GetToolSuffixType(1.550), // 基于孔径计算 ToolCategory = ToolItem.GetToolCategory(ToolItem.GetToolSuffixType(1.550)), HoleLocations = new List { "X-065975Y115250", "X-085825Y122450", "X-085825Y124550", "X-097425Y115250", "X103093Y502000" } }); Tools.Add(new ToolItem { ToolNumber = 3, Diameter = 1.156, // 尾号6 -> EA型槽刀 // 孔数相关属性已移除 // RegularHoles = 1, // SlotHoles = 528, // TotalHoles = 529, ToolType = ToolType.Slot, ToolSuffixType = ToolItem.GetToolSuffixType(1.156), // 基于孔径计算 ToolCategory = ToolItem.GetToolCategory(ToolItem.GetToolSuffixType(1.156)), HoleLocations = new List { "X-069659Y016450G85X-094159Y016450", "X-181341Y195550G85X-156841Y195550", "X-069659Y210450G85X-094159Y210450", "X-181341Y389550G85X-156841Y389550", "X-069659Y404450G85X-094159Y404450", "X-181341Y583550G85X-156841Y583550", "X162939Y596000" } }); Tools.Add(new ToolItem { ToolNumber = 4, Diameter = 1.451, // 尾号1 -> 槽刀 // 孔数相关属性已移除 // RegularHoles = 57, // SlotHoles = 0, // TotalHoles = 57, ToolType = ToolType.Regular, ToolSuffixType = ToolItem.GetToolSuffixType(1.451), // 基于孔径计算 ToolCategory = ToolItem.GetToolCategory(ToolItem.GetToolSuffixType(1.451)), HoleLocations = new List { "X-065975Y115250", "X-085825Y122450", "X-085825Y124550", "X-097425Y115250", "X103093Y502000" } }); Tools.Add(new ToolItem { ToolNumber = 5, Diameter = 1.153, // 尾号3 -> 粉尘刀 // 孔数相关属性已移除 // RegularHoles = 10, // SlotHoles = 0, // TotalHoles = 10, ToolType = ToolType.Regular, ToolSuffixType = ToolItem.GetToolSuffixType(1.153), // 基于孔径计算 ToolCategory = ToolItem.GetToolCategory(ToolItem.GetToolSuffixType(1.153)), HoleLocations = new List { "X-065975Y115250", "X-085825Y122450", "X-085825Y124550", "X-097425Y115250", "X103093Y502000" } }); Tools.Add(new ToolItem { ToolNumber = 6, Diameter = 0.499, // 特殊孔径固定为圆孔(机台码) // 孔数相关属性已移除 // RegularHoles = 57, // SlotHoles = 0, // TotalHoles = 57, ToolType = ToolType.MachineCode, MachineCodeCommand = "M97", MachineCodeType = "A*", ToolSuffixType = ToolItem.GetToolSuffixType(0.499), // 特殊孔径 ToolCategory = ToolItem.GetToolCategory(ToolItem.GetToolSuffixType(0.499)), HoleLocations = new List { "X-194000Y002000" } // 机台码刀具的坐标数据 }); // 更新按钮状态 UpdateMoveButtonsState(); // 加载示例钻带内容 DrillTapeContent = @"M48 ;厚铜板参数-镀膜-EA-250618 T01C1.049H05000Z+0.000S060.00F105.0U0700.0 T02C1.550H01500Z+0.150S070.00F008.0U0800.0 T03C1.156H03000Z-0.200S040.00F030.0U0900.0 T04C1.451H01500Z+0.150S070.00F008.0U0800.0 T05C1.153H01500Z+0.150S070.00F008.0U0800.0 T06C0.499H01500Z+0.150S070.00F008.0U0800.0 % T01 X-167525Y013500 X-167525Y018500 X-167525Y023500 X167525Y013500 X167525Y018500 X167525Y023500 X099366Y502000 T02 X-065975Y115250 X-085825Y122450 X-085825Y124550 X-097425Y115250 X103093Y502000 T03 X-069659Y016450G85X-094159Y016450 X-181341Y195550G85X-156841Y195550 X-069659Y210450G85X-094159Y210450 X-181341Y389550G85X-156841Y389550 X-069659Y404450G85X-094159Y404450 X-181341Y583550G85X-156841Y583550 X162939Y596000 T04 X-065975Y115250 X-085825Y122450 X-085825Y124550 X-097425Y115250 X103093Y502000 T05 X-065975Y115250 X-085825Y122450 X-085825Y124550 X-097425Y115250 X103093Y502000 T06 M97,A*,$S $N X-194000Y002000 M30"; } public event PropertyChangedEventHandler? PropertyChanged; protected bool SetProperty(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } /// /// 测试机台码孔数计算功能 /// public void TestMachineCodeHoleCalculation() { Console.WriteLine("=== 机台码孔数计算测试 ==="); // 测试钻带内容 string drillTapeContent = @"M48 ;厚铜板参数-镀膜-EA-250618 T01C0.799H05000Z+0.000S060.00F105.0U0700.0 T02C0.656H01500Z+0.150S070.00F008.0U0800.0 T03C1.601H03000Z-0.200S040.00F030.0U0900.0 T04C0.499 % T01 X-167525Y013500 X-167525Y018500 X-167525Y023500 X167525Y013500 X167525Y018500 X167525Y023500 X099366Y502000 T02 X-065975Y115250 X-085825Y122450 X-085825Y124550 X-097425Y115250 X103093Y502000 T03 X-069659Y016450G85X-094159Y016450 X-181341Y195550G85X-156841Y195550 X-069659Y210450G85X-094159Y210450 X-181341Y389550G85X-156841Y389550 X-069659Y404450G85X-094159Y404450 X-181341Y583550G85X-156841Y583550 X162939Y596000 T04 M97,A*,$S $N X-194000Y002000 M30"; // 处理钻带 var result = DrillTapeProcessor.ProcessDrillTape(drillTapeContent); // 输出结果 Console.WriteLine($"处理状态: {(result.Success ? "成功" : "失败")}"); if (!result.Success) { Console.WriteLine($"错误信息: {result.Message}"); return; } Console.WriteLine("\n刀具统计:"); Console.WriteLine("刀具\t孔径(mm)\t类型\t\t普通孔数\t槽孔数\t总孔数\t孔位数量"); Console.WriteLine("========================================================================"); foreach (var tool in result.ToolResults) { string toolTypeDisplay = tool.ToolType switch { ToolType.Regular => "圆孔", ToolType.Slot => "槽孔", ToolType.MachineCode => "机台码", _ => "未知" }; Console.WriteLine($"T{tool.ToolNumber:D2}\t{tool.Diameter:F3}\t\t{toolTypeDisplay}\t{tool.RegularHoles}\t\t{tool.SlotHoles}\t{tool.TotalHoles}\t{tool.Locations?.Count ?? 0}"); } Console.WriteLine($"\n总孔数: {result.TotalHoles}"); // 验证结果 Console.WriteLine("\n=== 验证结果 ==="); VerifyResults(result); // 测试孔位数据 Console.WriteLine("\n=== 孔位数据测试 ==="); TestHoleLocations(result); } /// /// 测试孔位数据 /// /// 钻带处理结果 private void TestHoleLocations(DrillTapeResult result) { foreach (var tool in result.ToolResults) { Console.WriteLine($"\nT{tool.ToolNumber:D2} 孔位数据 ({tool.Locations?.Count ?? 0} 个):"); if (tool.Locations != null && tool.Locations.Count > 0) { foreach (var location in tool.Locations.Take(5)) // 只显示前5个 { Console.WriteLine($" {location}"); } if (tool.Locations.Count > 5) { Console.WriteLine($" ... 还有 {tool.Locations.Count - 5} 个孔位"); } } else { Console.WriteLine(" 无孔位数据"); } } } private void VerifyResults(DrillTapeResult result) { // CAM350的预期结果 var expectedResults = new[] { new { ToolNumber = 1, Diameter = 0.799, ExpectedHoles = 7 }, new { ToolNumber = 2, Diameter = 0.656, ExpectedHoles = 5 }, new { ToolNumber = 3, Diameter = 1.601, ExpectedHoles = 529 }, new { ToolNumber = 4, Diameter = 0.499, ExpectedHoles = 57 } }; bool allMatch = true; foreach (var expected in expectedResults) { var actual = result.ToolResults.Find(t => t.ToolNumber == expected.ToolNumber); if (actual != null) { bool match = Math.Abs(actual.Diameter - expected.Diameter) < 0.001 && actual.TotalHoles == expected.ExpectedHoles; Console.WriteLine($"T{expected.ToolNumber:D2} ({expected.Diameter:F3}mm): " + $"预期={expected.ExpectedHoles}, 实际={actual.TotalHoles}, " + $"{(match ? "✓" : "✗")}"); if (!match) allMatch = false; } else { Console.WriteLine($"T{expected.ToolNumber:D2}: 未找到结果 ✗"); allMatch = false; } } Console.WriteLine($"\n总体结果: {(allMatch ? "✓ 所有结果与CAM350一致" : "✗ 存在不一致的结果")}"); } /// /// 测试刀具尾号类型功能 /// public void TestToolSuffixTypeFunctionality() { Console.WriteLine("=== 刀具尾号类型功能测试 ==="); // 测试不同孔径的尾号类型 double[] testDiameters = { 1.049, 1.550, 1.156, 1.451, 1.153, 1.255, 1.266, 1.277, 1.288, 1.299 }; Console.WriteLine("孔径(mm)\t尾号\t尾号类型\t\t大类"); Console.WriteLine("=============================================="); foreach (double diameter in testDiameters) { string diameterStr = diameter.ToString("F3"); char lastChar = diameterStr[diameterStr.Length - 1]; int suffix = int.Parse(lastChar.ToString()); var suffixType = ToolItem.GetToolSuffixType(diameter); var category = ToolItem.GetToolCategory(suffixType); var suffixDisplay = ToolItem.GetToolSuffixTypeDisplay(suffixType); var categoryDisplay = ToolItem.GetToolCategoryDisplay(category); Console.WriteLine($"{diameter:F3}\t{suffix}\t{suffixDisplay}\t{categoryDisplay}"); } Console.WriteLine(); Console.WriteLine("=== 测试钻带处理功能 ==="); // 测试钻带处理 string drillTapeContent = @"M48 T10C1.049 T11C1.550 T12C1.156 T13C1.451 T14C1.153 T15C1.255 T16C1.266 T17C1.277 % T10 X01000Y01000 T11 X02000Y02000 T12 X03000Y03000 T13 X04000Y04000 T14 X05000Y05000 T15 X06000Y06000 T16 X07000Y07000 T17 X08000Y08000 M30"; var result = DrillTapeProcessor.ProcessDrillTape(drillTapeContent); if (result.Success) { Console.WriteLine("钻带处理成功!"); Console.WriteLine(); Console.WriteLine("刀具编号\t孔径(mm)\t类型\t\t尾号类型\t大类\t\t孔数"); Console.WriteLine("================================================================"); foreach (var tool in result.ToolResults) { string toolTypeDisplay = tool.ToolType switch { ToolType.Regular => "圆孔", ToolType.Slot => "槽孔", ToolType.MachineCode => "机台码", _ => "未知" }; string suffixTypeDisplay = tool.ToolSuffixType switch { ToolSuffixType.Drill => "钻针", ToolSuffixType.Slot => "槽刀", ToolSuffixType.EASlot => "EA型槽刀", ToolSuffixType.DustSlot => "粉尘刀", ToolSuffixType.DeburrSlot => "去毛刺刀", ToolSuffixType.NonStandard => "非标刀", ToolSuffixType.EASlot2 => "EA型槽刀", ToolSuffixType.Special => "特殊刀具", _ => "未知" }; string categoryDisplay = tool.ToolCategory switch { ToolCategory.Drill => "钻针", ToolCategory.Slot => "槽刀", ToolCategory.EA => "EA刀", ToolCategory.NonStandard => "非标刀", ToolCategory.Special => "特殊刀", _ => "未知" }; Console.WriteLine($"T{tool.ToolNumber:D2}\t{tool.Diameter:F3}\t\t{toolTypeDisplay}\t{suffixTypeDisplay}\t{categoryDisplay}\t{tool.TotalHoles}"); } } else { Console.WriteLine($"钻带处理失败: {result.Message}"); } Console.WriteLine(); Console.WriteLine("测试完成!"); } /// /// 测试孔位数据功能(可在应用启动时调用) /// public static void TestHoleLocationsFunctionality() { Console.WriteLine("=== 孔位数据功能测试 ==="); Console.WriteLine(); // 使用用户提供的钻带数据示例 string drillTapeContent = @"M48 T01C0.799H05000Z+0.000S060.00F105.0U0700.0 T02C1.049H05000Z+0.000S045.00F105.0U0700.0 % T01 X-281000Y003000 X-276000Y003000 X-271000Y003000 X271000Y003000 X276000Y003000 X281000Y003000 X-281000Y702500 X-276000Y702500 X-271000Y702500 X271000Y703000 X276000Y703000 X281000Y703000 X077370Y704000 T02 X-100000Y100000 X-200000Y200000 X-300000Y300000 M30"; // 处理钻带 var result = DrillTapeProcessor.ProcessDrillTape(drillTapeContent); // 输出结果 Console.WriteLine($"处理状态: {(result.Success ? "成功" : "失败")}"); if (!result.Success) { Console.WriteLine($"错误信息: {result.Message}"); return; } Console.WriteLine("\n刀具统计:"); Console.WriteLine("刀具\t孔径(mm)\t类型\t\t普通孔数\t槽孔数\t总孔数\t孔位数量"); Console.WriteLine("========================================================================"); foreach (var tool in result.ToolResults) { string toolTypeDisplay = tool.ToolType switch { ToolType.Regular => "圆孔", ToolType.Slot => "槽孔", ToolType.MachineCode => "机台码", _ => "未知" }; Console.WriteLine($"T{tool.ToolNumber:D2}\t{tool.Diameter:F3}\t\t{toolTypeDisplay}\t{tool.RegularHoles}\t\t{tool.SlotHoles}\t{tool.TotalHoles}\t{tool.Locations?.Count ?? 0}"); } Console.WriteLine($"\n总孔数: {result.TotalHoles}"); // 详细显示孔位数据 Console.WriteLine("\n=== 详细孔位数据 ==="); foreach (var tool in result.ToolResults) { Console.WriteLine($"\nT{tool.ToolNumber:D2} 孔位数据 ({tool.Locations?.Count ?? 0} 个):"); if (tool.Locations != null && tool.Locations.Count > 0) { int count = 0; foreach (var location in tool.Locations) { Console.WriteLine($" [{++count:D2}] {location}"); } } else { Console.WriteLine(" 无孔位数据"); } } // 验证T01的孔位数据是否符合预期 Console.WriteLine("\n=== 验证T01孔位数据 ==="); var t01Result = result.ToolResults.Find(t => t.ToolNumber == 1); if (t01Result != null && t01Result.Locations != null) { var expectedLocations = new System.Collections.Generic.List { "X-281000Y003000", "X-276000Y003000", "X-271000Y003000", "X271000Y003000", "X276000Y003000", "X281000Y003000", "X-281000Y702500", "X-276000Y702500", "X-271000Y702500", "X271000Y703000", "X276000Y703000", "X281000Y703000", "X077370Y704000" }; bool allMatch = true; if (t01Result.Locations.Count == expectedLocations.Count) { for (int i = 0; i < expectedLocations.Count; i++) { if (t01Result.Locations[i] != expectedLocations[i]) { Console.WriteLine($" 位置 {i + 1}: 预期 {expectedLocations[i]}, 实际 {t01Result.Locations[i]} ✗"); allMatch = false; } else { Console.WriteLine($" 位置 {i + 1}: {t01Result.Locations[i]} ✓"); } } } else { Console.WriteLine($" 孔位数量不匹配: 预期 {expectedLocations.Count}, 实际 {t01Result.Locations.Count} ✗"); allMatch = false; } Console.WriteLine($"\nT01孔位数据验证结果: {(allMatch ? "✓ 全部匹配" : "✗ 存在不匹配")}"); } else { Console.WriteLine("未找到T01刀具数据 ✗"); } Console.WriteLine("\n孔位数据功能测试完成!"); } /// /// 显示刀具详情窗口 /// /// 要显示详情的刀具 public void ShowToolDetail(ToolItem tool) { if (tool == null) return; try { var detailWindow = new ToolDetailWindow(tool); detailWindow.Owner = System.Windows.Application.Current.MainWindow; detailWindow.ShowDialog(); } catch (Exception ex) { System.Windows.MessageBox.Show($"显示刀具详情失败: {ex.Message}", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); } } /// /// 测试重排刀序功能 /// public void TestReorderAndRenumberTools() { Console.WriteLine("=== 重排刀序功能测试 ==="); // 1. 加载测试数据 LoadSampleData(); // 2. 记录原始状态 var originalOrder = Tools.Select(t => new { t.ToolNumber, t.Diameter, LocationCount = t.HoleLocations?.Count ?? 0, FirstLocation = t.HoleLocations?.FirstOrDefault() ?? "" }).ToList(); Console.WriteLine("原始刀具顺序:"); foreach (var tool in originalOrder) { Console.WriteLine($"T{tool.ToolNumber:D2}({tool.Diameter:F3}): {tool.LocationCount}个坐标, 首个坐标: {tool.FirstLocation}"); } // 3. 执行重排操作(将T02移到第一位) if (Tools.Count >= 2) { var toolToMove = Tools.FirstOrDefault(t => t.ToolNumber == 2); if (toolToMove != null && toolToMove.ToolType != ToolType.MachineCode) { int oldIndex = Tools.IndexOf(toolToMove); ReorderTools(oldIndex, 0); } } // 4. 执行重新编号 string reorderedDrillTape = ReorderAndRenumberTools(); // 5. 验证结果 Console.WriteLine("\n重排后刀具顺序:"); var reorderedOrder = Tools.Select(t => new { t.ToolNumber, t.Diameter, LocationCount = t.HoleLocations?.Count ?? 0, FirstLocation = t.HoleLocations?.FirstOrDefault() ?? "" }).ToList(); foreach (var tool in reorderedOrder) { Console.WriteLine($"T{tool.ToolNumber:D2}({tool.Diameter:F3}): {tool.LocationCount}个坐标, 首个坐标: {tool.FirstLocation}"); } // 6. 验证钻带内容 Console.WriteLine("\n重排后的钻带内容:"); Console.WriteLine(reorderedDrillTape); // 7. 验证坐标跟随 VerifyCoordinateBinding(originalOrder.ToList(), reorderedOrder.ToList()); Console.WriteLine("\n重排刀序功能测试完成!"); } /// /// 验证坐标绑定关系 /// private void VerifyCoordinateBinding(List originalOrder, List reorderedOrder) { Console.WriteLine("\n=== 验证坐标绑定关系 ==="); // 创建直径到坐标的映射 var originalDiameterToLocation = new Dictionary(); foreach (var tool in originalOrder) { originalDiameterToLocation[tool.Diameter] = tool.FirstLocation; } // 验证重排后的坐标绑定 bool allMatch = true; foreach (var tool in reorderedOrder) { if (originalDiameterToLocation.ContainsKey(tool.Diameter)) { string originalLocation = originalDiameterToLocation[tool.Diameter]; if (tool.FirstLocation != originalLocation) { Console.WriteLine($"✗ 刀具{tool.Diameter:F3}的坐标不匹配: 原始{originalLocation}, 重排后{tool.FirstLocation}"); allMatch = false; } else { Console.WriteLine($"✓ 刀具{tool.Diameter:F3}的坐标正确跟随: {tool.FirstLocation}"); } } } Console.WriteLine($"\n坐标绑定验证结果: {(allMatch ? "✓ 全部正确" : "✗ 存在问题")}"); } /// /// 测试修正后的重排刀序功能 /// public void TestFixedReorderFunction() { Console.WriteLine("=== 测试修正后的重排刀序功能 ==="); // 1. 加载测试数据 LoadSampleData(); Console.WriteLine("原始刀具顺序:"); foreach (var tool in Tools) { Console.WriteLine($"T{tool.ToolNumber:D2}C{tool.Diameter:F3}"); } // 2. 模拟用户重排操作:将T02移到第一位 if (Tools.Count >= 2) { var toolToMove = Tools.FirstOrDefault(t => t.ToolNumber == 2); if (toolToMove != null && toolToMove.ToolType != ToolType.MachineCode) { int oldIndex = Tools.IndexOf(toolToMove); ReorderTools(oldIndex, 0); Console.WriteLine("\n重排后刀具顺序(重新编号前):"); foreach (var tool in Tools) { Console.WriteLine($"T{tool.ToolNumber:D2}C{tool.Diameter:F3}"); } // 3. 执行重新编号 string reorderedDrillTape = ReorderAndRenumberTools(); Console.WriteLine("\n重排并重新编号后的刀具顺序:"); foreach (var tool in Tools) { Console.WriteLine($"T{tool.ToolNumber:D2}C{tool.Diameter:F3}"); } // 4. 验证刀具定义部分是否按顺序排列 Console.WriteLine("\n=== 验证结果 ==="); var lines = reorderedDrillTape.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); var toolDefinitionOrder = new List(); foreach (var line in lines) { if (line.Trim() == "%") { break; } if (Regex.IsMatch(line, @"^T(\d+)C")) { var match = Regex.Match(line, @"^T(\d+)C"); if (match.Success) { toolDefinitionOrder.Add(int.Parse(match.Groups[1].Value)); } } } Console.WriteLine("刀具定义部分的顺序: " + string.Join(", ", toolDefinitionOrder.Select(t => $"T{t:D2}"))); bool isOrdered = true; for (int i = 1; i < toolDefinitionOrder.Count; i++) { if (toolDefinitionOrder[i] < toolDefinitionOrder[i - 1]) { isOrdered = false; break; } } Console.WriteLine($"刀具定义部分是否按顺序排列: {(isOrdered ? "是" : "否")}"); if (isOrdered) { Console.WriteLine("✓ 重排刀序功能修正成功!"); } else { Console.WriteLine("✗ 重排刀序功能仍有问题!"); } // 5. 显示完整的重排后钻带内容 Console.WriteLine("\n重排后的钻带内容:"); Console.WriteLine(reorderedDrillTape); } } } /// /// 测试机台码坐标数据完整性 /// public void TestMachineCodeCoordinateIntegrity() { Console.WriteLine("=== 机台码坐标数据完整性测试 ==="); // 1. 加载示例数据 LoadSampleData(); // 2. 执行重排刀序操作 string reorderedDrillTape = ReorderAndRenumberTools(); // 3. 验证机台码坐标数据 Console.WriteLine("重排后的钻带内容:"); Console.WriteLine(reorderedDrillTape); // 4. 检查机台码部分是否包含坐标数据 var lines = reorderedDrillTape.Split(new[] { '\r', '\n' }, StringSplitOptions.None); bool foundMachineCode = false; bool foundCoordinate = false; int machineCodeToolNumber = -1; for (int i = 0; i < lines.Length; i++) { string line = lines[i].Trim(); // 查找机台码刀具 if (Regex.IsMatch(line, @"^T(\d+)")) { var match = Regex.Match(line, @"^T(\d+)"); if (match.Success) { int toolNumber = int.Parse(match.Groups[1].Value); var tool = Tools.FirstOrDefault(t => t.ToolNumber == toolNumber); if (tool != null && tool.ToolType == ToolType.MachineCode) { foundMachineCode = true; machineCodeToolNumber = toolNumber; Console.WriteLine($"\n找到机台码刀具 T{toolNumber:D2}"); // 检查下一行是否是机台码命令 if (i + 1 < lines.Length) { string nextLine = lines[i + 1].Trim(); if (Regex.IsMatch(nextLine, @"(M97|M98),(A\*|B\*),\$S \$N")) { Console.WriteLine($" 机台码命令: {nextLine}"); // 检查下下行是否是坐标数据 if (i + 2 < lines.Length) { string coordinateLine = lines[i + 2].Trim(); if (Regex.IsMatch(coordinateLine, @"X([+-]?\d+\.?\d*)Y([+-]?\d+\.?\d*)")) { foundCoordinate = true; Console.WriteLine($" 坐标数据: {coordinateLine}"); } } } } } } } } // 5. 输出测试结果 Console.WriteLine("\n=== 测试结果 ==="); Console.WriteLine($"找到机台码刀具: {(foundMachineCode ? "是" : "否")}"); Console.WriteLine($"找到坐标数据: {(foundCoordinate ? "是" : "否")}"); if (foundMachineCode && foundCoordinate) { Console.WriteLine("✓ 机台码坐标数据完整性测试通过!"); } else { Console.WriteLine("✗ 机台码坐标数据完整性测试失败!"); if (!foundMachineCode) Console.WriteLine(" 原因:未找到机台码刀具"); if (!foundCoordinate) Console.WriteLine(" 原因:机台码刀具缺少坐标数据"); } // 6. 验证ToolItem中的坐标数据 var machineCodeTool = Tools.FirstOrDefault(t => t.ToolType == ToolType.MachineCode); if (machineCodeTool != null) { Console.WriteLine($"\nToolItem中的机台码坐标数据:"); Console.WriteLine($" 刀具编号: T{machineCodeTool.ToolNumber:D2}"); Console.WriteLine($" 机台码命令: {machineCodeTool.MachineCodeCommand}"); Console.WriteLine($" 机台码类型: {machineCodeTool.MachineCodeType}"); Console.WriteLine($" 坐标数量: {machineCodeTool.HoleLocations?.Count ?? 0}"); if (machineCodeTool.HoleLocations != null && machineCodeTool.HoleLocations.Count > 0) { foreach (var location in machineCodeTool.HoleLocations) { Console.WriteLine($" 坐标: {location}"); } } } } /// /// 测试机台码处理修复效果 /// public void TestMachineCodeProcessingFix() { Console.WriteLine("=== 测试机台码处理修复效果 ==="); // 测试钻带内容(包含机台码) string testDrillTape = @"M48 ;厚铜板参数-镀膜-EA-250618 T01C1.049H05000Z+0.000S060.00F105.0U0700.0 T02C1.550H01500Z+0.150S070.00F008.0U0800.0 T03C1.156H03000Z-0.200S040.00F030.0U0900.0 T04C0.499H01500Z+0.150S070.00F008.0U0800.0 % T01 X-167525Y013500 X-167525Y018500 X-167525Y023500 T02 X-065975Y115250 X-085825Y122450 T03 X-069659Y016450G85X-094159Y016450 X-181341Y195550G85X-156841Y195550 T04 M97,A*,$S $N X-194000Y002000 M30"; try { // 1. 使用DrillTapeProcessor处理钻带 Console.WriteLine("\n1. 使用DrillTapeProcessor处理钻带:"); var result = DrillTapeProcessor.ProcessDrillTape(testDrillTape); if (!result.Success) { Console.WriteLine($"处理失败: {result.Message}"); return; } // 2. 检查ToolResult中的机台码信息 Console.WriteLine("\n2. 检查ToolResult中的机台码信息:"); foreach (var toolResult in result.ToolResults) { Console.WriteLine($"T{toolResult.ToolNumber:D2}: 类型={toolResult.ToolType}, 命令={toolResult.MachineCodeCommand}, 类型={toolResult.MachineCodeType}"); } // 3. 使用LoadToolsFromDrillTape方法加载到ViewModel Console.WriteLine("\n3. 加载到ViewModel并检查ToolItem中的机台码信息:"); DrillTapeContent = testDrillTape; Tools.Clear(); LoadToolsFromDrillTape(testDrillTape); foreach (var tool in Tools) { Console.WriteLine($"T{tool.ToolNumber:D2}: 类型={tool.ToolType}, 命令={tool.MachineCodeCommand}, 类型={tool.MachineCodeType}"); } // 4. 测试GenerateReorderedDrillTape方法 Console.WriteLine("\n4. 测试GenerateReorderedDrillTape方法:"); string reorderedDrillTape = DrillTapeProcessorExtensions.GenerateReorderedDrillTape(testDrillTape, Tools.ToList()); Console.WriteLine("重排后的钻带内容:"); Console.WriteLine(reorderedDrillTape); // 5. 验证机台码信息是否正确保留 Console.WriteLine("\n5. 验证机台码信息是否正确保留:"); bool machineCodeFound = false; bool machineCodeCommandFound = false; bool machineCodeTypeFound = false; var lines = reorderedDrillTape.Split(new[] { '\r', '\n' }, StringSplitOptions.None); foreach (var line in lines) { if (line.Contains("M97") || line.Contains("M98")) { machineCodeFound = true; if (line.Contains("M97") || line.Contains("M98")) { machineCodeCommandFound = true; } if (line.Contains("A*") || line.Contains("B*")) { machineCodeTypeFound = true; } Console.WriteLine($"找到机台码命令行: {line}"); } } Console.WriteLine($"\n验证结果:"); Console.WriteLine($"机台码命令存在: {machineCodeFound}"); Console.WriteLine($"机台码命令类型正确: {machineCodeCommandFound}"); Console.WriteLine($"机台码类型正确: {machineCodeTypeFound}"); if (machineCodeFound && machineCodeCommandFound && machineCodeTypeFound) { Console.WriteLine("\n✓ 机台码处理修复效果验证成功!"); } else { Console.WriteLine("\n✗ 机台码处理修复效果验证失败!"); } } catch (Exception ex) { Console.WriteLine($"测试过程中发生异常: {ex.Message}"); Console.WriteLine($"堆栈跟踪: {ex.StackTrace}"); } } } }