Refactor drill tape reading and reorder logic
This commit is contained in:
13
.claude/settings.local.json
Normal file
13
.claude/settings.local.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(git config:*)",
|
||||||
|
"Bash(git log:*)",
|
||||||
|
"Bash(git add:*)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(git push:*)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
67
AGENTS.md
Normal file
67
AGENTS.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
DrillTools (钻带处理工具) is a Windows desktop application for processing PCB drill tape files. It parses drill tape data, displays tool information (tool number, diameter, hole count, parameters), and supports reordering tools with various sorting methods.
|
||||||
|
|
||||||
|
## Build & Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet build # Build the project
|
||||||
|
dotnet build -c Release # Build in Release mode
|
||||||
|
dotnet publish # Publish as single-file exe (win-x86)
|
||||||
|
```
|
||||||
|
|
||||||
|
Target: .NET 6.0, WPF, x86 only. No external NuGet dependencies.
|
||||||
|
|
||||||
|
No test framework is configured. Do not write unit tests for this project.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
**MVVM pattern** with three windows:
|
||||||
|
|
||||||
|
- **MainWindow** — primary UI for loading, viewing, and reordering drill tape tools
|
||||||
|
- **ToolDetailWindow** — displays detailed tool parameters
|
||||||
|
- **ToolReorderConfirmationWindow** — confirmation dialog for reorder operations
|
||||||
|
|
||||||
|
**Key files:**
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `MainWindowViewModel.cs` (~2400 lines) | Central business logic: tool management, drill tape parsing/generation, sort seed management, reference tape comparison |
|
||||||
|
| `DrillTapeProcessor.cs` | Core drill tape parsing engine (`DrillTools.Integration` namespace) |
|
||||||
|
| `ToolItem.cs` | Data model for drill tools (implements `INotifyPropertyChanged`) |
|
||||||
|
| `SlotHoleCalculator.cs` | Geometry calculations for slot hole counts and positions |
|
||||||
|
| `DragDropHelper.cs` | WPF ListView drag-drop with visual insertion indicator |
|
||||||
|
|
||||||
|
**Namespaces:** `DrillTools` (UI/models), `DrillTools.Integration` (parsing logic).
|
||||||
|
|
||||||
|
## Drill Tape Format
|
||||||
|
|
||||||
|
The app parses a specific PCB drill tape format:
|
||||||
|
|
||||||
|
```
|
||||||
|
M48 ← Header start
|
||||||
|
T01C0.799H05000Z+0.000S060.00 ← Tool definitions (Txx=tool#, C=diameter, rest=machine params)
|
||||||
|
T02C0.656H01500Z+0.150S070.00
|
||||||
|
% ← Header end / data start
|
||||||
|
T01 ← Active tool
|
||||||
|
X-167525Y013500 ← Hole coordinates
|
||||||
|
X-069659Y016450G85X-094159Y016450 ← Slot hole (start G85 end)
|
||||||
|
M30 ← End of file
|
||||||
|
```
|
||||||
|
|
||||||
|
Supported file extensions: `.txt`, `.drl`, `.dr2`, `.dpin`
|
||||||
|
|
||||||
|
**Tool types by diameter suffix digit:** 0/8/9=Drill, 1=Slot, 2/6=EA Slot, 3=Dust Slot, 4=Deburr, 5=NonStandard, 7=Special.
|
||||||
|
|
||||||
|
## Important Technical Details
|
||||||
|
|
||||||
|
- **File encoding**: ANSI/GB2312 (code page 936) — drill tape files use this encoding, not UTF-8
|
||||||
|
- **Encrypted file reading**: Uses `cmd.exe /c type` to read drill tape files (some files are "encrypted" and cannot be read directly via standard file I/O)
|
||||||
|
- **Slot hole calculation**: Uses CAM350 standard tolerance (0.0127mm) for computing hole counts along slot paths
|
||||||
|
- **Backup strategy**: Creates `.bak` files when saving modified drill tape data
|
||||||
|
- **Command-line support**: App accepts a file path argument to auto-load a drill tape file on startup
|
||||||
|
- **Documentation**: All docs under `Docs/` are in Chinese (Simplified). The UI is also in Chinese.
|
||||||
67
CLAUDE.md
Normal file
67
CLAUDE.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
DrillTools (钻带处理工具) is a Windows desktop application for processing PCB drill tape files. It parses drill tape data, displays tool information (tool number, diameter, hole count, parameters), and supports reordering tools with various sorting methods.
|
||||||
|
|
||||||
|
## Build & Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet build # Build the project
|
||||||
|
dotnet build -c Release # Build in Release mode
|
||||||
|
dotnet publish # Publish as single-file exe (win-x86)
|
||||||
|
```
|
||||||
|
|
||||||
|
Target: .NET 6.0, WPF, x86 only. No external NuGet dependencies.
|
||||||
|
|
||||||
|
No test framework is configured. Do not write unit tests for this project.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
**MVVM pattern** with three windows:
|
||||||
|
|
||||||
|
- **MainWindow** — primary UI for loading, viewing, and reordering drill tape tools
|
||||||
|
- **ToolDetailWindow** — displays detailed tool parameters
|
||||||
|
- **ToolReorderConfirmationWindow** — confirmation dialog for reorder operations
|
||||||
|
|
||||||
|
**Key files:**
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `MainWindowViewModel.cs` (~2400 lines) | Central business logic: tool management, drill tape parsing/generation, sort seed management, reference tape comparison |
|
||||||
|
| `DrillTapeProcessor.cs` | Core drill tape parsing engine (`DrillTools.Integration` namespace) |
|
||||||
|
| `ToolItem.cs` | Data model for drill tools (implements `INotifyPropertyChanged`) |
|
||||||
|
| `SlotHoleCalculator.cs` | Geometry calculations for slot hole counts and positions |
|
||||||
|
| `DragDropHelper.cs` | WPF ListView drag-drop with visual insertion indicator |
|
||||||
|
|
||||||
|
**Namespaces:** `DrillTools` (UI/models), `DrillTools.Integration` (parsing logic).
|
||||||
|
|
||||||
|
## Drill Tape Format
|
||||||
|
|
||||||
|
The app parses a specific PCB drill tape format:
|
||||||
|
|
||||||
|
```
|
||||||
|
M48 ← Header start
|
||||||
|
T01C0.799H05000Z+0.000S060.00 ← Tool definitions (Txx=tool#, C=diameter, rest=machine params)
|
||||||
|
T02C0.656H01500Z+0.150S070.00
|
||||||
|
% ← Header end / data start
|
||||||
|
T01 ← Active tool
|
||||||
|
X-167525Y013500 ← Hole coordinates
|
||||||
|
X-069659Y016450G85X-094159Y016450 ← Slot hole (start G85 end)
|
||||||
|
M30 ← End of file
|
||||||
|
```
|
||||||
|
|
||||||
|
Supported file extensions: `.txt`, `.drl`, `.dr2`, `.dpin`
|
||||||
|
|
||||||
|
**Tool types by diameter suffix digit:** 0/8/9=Drill, 1=Slot, 2/6=EA Slot, 3=Dust Slot, 4=Deburr, 5=NonStandard, 7=Special.
|
||||||
|
|
||||||
|
## Important Technical Details
|
||||||
|
|
||||||
|
- **File encoding**: ANSI/GB2312 (code page 936) — drill tape files use this encoding, not UTF-8
|
||||||
|
- **Encrypted file reading**: Uses `cmd.exe /c type` to read drill tape files (some files are "encrypted" and cannot be read directly via standard file I/O)
|
||||||
|
- **Slot hole calculation**: Uses CAM350 standard tolerance (0.0127mm) for computing hole counts along slot paths
|
||||||
|
- **Backup strategy**: Creates `.bak` files when saving modified drill tape data
|
||||||
|
- **Command-line support**: App accepts a file path argument to auto-load a drill tape file on startup
|
||||||
|
- **Documentation**: All docs under `Docs/` are in Chinese (Simplified). The UI is also in Chinese.
|
||||||
92
CommandTypeFileReader.cs
Normal file
92
CommandTypeFileReader.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DrillTools
|
||||||
|
{
|
||||||
|
internal static class CommandTypeFileReader
|
||||||
|
{
|
||||||
|
private const int Gb2312CodePage = 936;
|
||||||
|
|
||||||
|
private static readonly char[] ForbiddenPathChars =
|
||||||
|
{
|
||||||
|
'&', '|', '<', '>', '^', '%', '!', '(', ')', '@', '"', '\r', '\n'
|
||||||
|
};
|
||||||
|
|
||||||
|
public static string ReadAllText(string filePath)
|
||||||
|
{
|
||||||
|
return ReadAllText(filePath, CreateAnsiEncoding());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ReadAllText(string filePath, Encoding encoding)
|
||||||
|
{
|
||||||
|
string normalizedPath = ValidateAndNormalizePath(filePath);
|
||||||
|
|
||||||
|
using var process = new Process
|
||||||
|
{
|
||||||
|
StartInfo = CreateStartInfo(normalizedPath, encoding)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!process.Start())
|
||||||
|
throw new InvalidOperationException("无法启动文件读取进程");
|
||||||
|
|
||||||
|
var outputTask = process.StandardOutput.ReadToEndAsync();
|
||||||
|
var errorTask = process.StandardError.ReadToEndAsync();
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
string output = outputTask.GetAwaiter().GetResult();
|
||||||
|
string error = errorTask.GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
if (process.ExitCode != 0)
|
||||||
|
throw new InvalidOperationException($"读取文件失败,退出代码:{process.ExitCode},错误:{error.Trim()}");
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProcessStartInfo CreateStartInfo(string filePath, Encoding encoding)
|
||||||
|
{
|
||||||
|
return new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "cmd.exe",
|
||||||
|
Arguments = $"/d /c type \"{filePath}\"",
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
StandardOutputEncoding = encoding,
|
||||||
|
StandardErrorEncoding = encoding
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ValidateAndNormalizePath(string filePath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(filePath))
|
||||||
|
throw new ArgumentException("文件路径不能为空", nameof(filePath));
|
||||||
|
|
||||||
|
if (filePath.IndexOfAny(ForbiddenPathChars) >= 0)
|
||||||
|
throw new ArgumentException("文件路径包含不允许的命令行特殊字符", nameof(filePath));
|
||||||
|
|
||||||
|
string normalizedPath = Path.GetFullPath(filePath);
|
||||||
|
if (normalizedPath.IndexOfAny(ForbiddenPathChars) >= 0)
|
||||||
|
throw new ArgumentException("文件路径包含不允许的命令行特殊字符", nameof(filePath));
|
||||||
|
|
||||||
|
if (!File.Exists(normalizedPath))
|
||||||
|
throw new FileNotFoundException($"文件不存在:{normalizedPath}", normalizedPath);
|
||||||
|
|
||||||
|
return normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Encoding CreateAnsiEncoding()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Encoding.GetEncoding(Gb2312CodePage);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Encoding.Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -549,7 +549,7 @@ namespace DrillTools.Integration
|
|||||||
/// <param name="toolNumberMapping">刀具编号映射</param>
|
/// <param name="toolNumberMapping">刀具编号映射</param>
|
||||||
/// <param name="reorderedTools">重新排序的刀具列表</param>
|
/// <param name="reorderedTools">重新排序的刀具列表</param>
|
||||||
/// <returns>更新后的钻带内容</returns>
|
/// <returns>更新后的钻带内容</returns>
|
||||||
private static string UpdateDrillTapeWithNewToolNumbers(string originalDrillTape, Dictionary<int, int> toolNumberMapping, List<ToolItem> reorderedTools)
|
public static string UpdateDrillTapeWithNewToolNumbers(string originalDrillTape, Dictionary<int, int> toolNumberMapping, List<ToolItem> reorderedTools)
|
||||||
{
|
{
|
||||||
var lines = originalDrillTape.Split(new[] { '\r', '\n' }, StringSplitOptions.None);
|
var lines = originalDrillTape.Split(new[] { '\r', '\n' }, StringSplitOptions.None);
|
||||||
var result = new List<string>();
|
var result = new List<string>();
|
||||||
@@ -709,4 +709,4 @@ namespace DrillTools.Integration
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
|
||||||
@@ -70,22 +68,7 @@ namespace DrillTools
|
|||||||
// 异步加载文件以避免阻塞UI
|
// 异步加载文件以避免阻塞UI
|
||||||
await System.Threading.Tasks.Task.Run(() =>
|
await System.Threading.Tasks.Task.Run(() =>
|
||||||
{
|
{
|
||||||
// 使用与现有代码相同的方式读取文件
|
string drillTapeContent = CommandTypeFileReader.ReadAllText(filePath);
|
||||||
var process = new System.Diagnostics.Process
|
|
||||||
{
|
|
||||||
StartInfo = new System.Diagnostics.ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "cmd.exe",
|
|
||||||
Arguments = $"/c type \"{filePath}\"",
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
string drillTapeContent = process.StandardOutput.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
// 在UI线程中更新界面
|
// 在UI线程中更新界面
|
||||||
this.Dispatcher.Invoke(() =>
|
this.Dispatcher.Invoke(() =>
|
||||||
@@ -160,22 +143,7 @@ namespace DrillTools
|
|||||||
// 保存原始文件路径
|
// 保存原始文件路径
|
||||||
ViewModel.OriginalFilePath = openFileDialog.FileName;
|
ViewModel.OriginalFilePath = openFileDialog.FileName;
|
||||||
|
|
||||||
// 使用 cmd 命令读取加密钻带文件
|
string drillTapeContent = CommandTypeFileReader.ReadAllText(openFileDialog.FileName);
|
||||||
var process = new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "cmd.exe",
|
|
||||||
Arguments = $"/c type \"{openFileDialog.FileName}\"",
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
string drillTapeContent = process.StandardOutput.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
ViewModel.LoadToolsFromDrillTape(drillTapeContent);
|
ViewModel.LoadToolsFromDrillTape(drillTapeContent);
|
||||||
}
|
}
|
||||||
@@ -342,21 +310,7 @@ namespace DrillTools
|
|||||||
// 保存原始文件路径
|
// 保存原始文件路径
|
||||||
ViewModel.OriginalFilePath = files[0];
|
ViewModel.OriginalFilePath = files[0];
|
||||||
|
|
||||||
var process = new Process
|
string drillTapeContent = CommandTypeFileReader.ReadAllText(files[0]);
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "cmd.exe",
|
|
||||||
Arguments = $"/c type \"{files[0]}\"",
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
string drillTapeContent = process.StandardOutput.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
ViewModel.LoadToolsFromDrillTape(drillTapeContent);
|
ViewModel.LoadToolsFromDrillTape(drillTapeContent);
|
||||||
}
|
}
|
||||||
@@ -369,4 +323,4 @@ namespace DrillTools
|
|||||||
base.OnDrop(e);
|
base.OnDrop(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -594,19 +594,22 @@ namespace DrillTools
|
|||||||
MachineCodeType = t.MachineCodeType
|
MachineCodeType = t.MachineCodeType
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
//重新排一下 reorderedTools 的刀序Txx
|
//检查是否所有刀序没有变化
|
||||||
|
bool hasOrderChanged = originalTools.Count != reorderedTools.Count;
|
||||||
|
for (int i = 0; i < originalTools.Count; i++)
|
||||||
|
{
|
||||||
|
if (hasOrderChanged)
|
||||||
|
break;
|
||||||
|
|
||||||
|
hasOrderChanged = reorderedTools[i].ToolNumber != originalTools[i].ToolNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
//重新排一下 reorderedTools 的刀序Txx,用于确认窗口展示
|
||||||
int number = 1;
|
int number = 1;
|
||||||
foreach (var item in reorderedTools)
|
foreach (var item in reorderedTools)
|
||||||
item.ToolNumber = number++;
|
item.ToolNumber = number++;
|
||||||
|
|
||||||
//检查是否所有刀序没有变化
|
if (!hasOrderChanged)
|
||||||
int checkindex = 1;
|
|
||||||
for (int i = 0; i < originalTools.Count; i++)
|
|
||||||
{
|
|
||||||
if (reorderedTools[i].ToolNumber == originalTools[i].ToolNumber)
|
|
||||||
checkindex++;
|
|
||||||
}
|
|
||||||
if (checkindex == originalTools.Count)
|
|
||||||
{
|
{
|
||||||
if (isApply)
|
if (isApply)
|
||||||
{
|
{
|
||||||
@@ -648,7 +651,8 @@ namespace DrillTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. 更新钻带内容中的刀具编号和孔位数据
|
// 3. 更新钻带内容中的刀具编号和孔位数据
|
||||||
string updatedDrillTape = UpdateDrillTapeWithNewToolNumbers(DrillTapeContent, toolNumberMapping);
|
string updatedDrillTape = DrillTapeProcessorExtensions.UpdateDrillTapeWithNewToolNumbers(
|
||||||
|
DrillTapeContent, toolNumberMapping, Tools.ToList());
|
||||||
|
|
||||||
// 4. 更新钻带内容
|
// 4. 更新钻带内容
|
||||||
DrillTapeContent = updatedDrillTape;
|
DrillTapeContent = updatedDrillTape;
|
||||||
@@ -662,132 +666,6 @@ namespace DrillTools
|
|||||||
return updatedDrillTape;
|
return updatedDrillTape;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用新的刀具编号更新钻带内容
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="originalDrillTape">原始钻带内容</param>
|
|
||||||
/// <param name="toolNumberMapping">刀具编号映射</param>
|
|
||||||
/// <returns>更新后的钻带内容</returns>
|
|
||||||
private string UpdateDrillTapeWithNewToolNumbers(string originalDrillTape, Dictionary<int, int> toolNumberMapping)
|
|
||||||
{
|
|
||||||
var lines = originalDrillTape.Split(new[] { '\r', '\n' }, StringSplitOptions.None);
|
|
||||||
var result = new List<string>();
|
|
||||||
|
|
||||||
// 创建新编号到刀具对象的映射,以便获取对应的坐标数据
|
|
||||||
var newNumberToToolMap = new Dictionary<int, ToolItem>();
|
|
||||||
foreach (var tool in Tools)
|
|
||||||
{
|
|
||||||
if (toolNumberMapping.ContainsValue(tool.ToolNumber))
|
|
||||||
{
|
|
||||||
newNumberToToolMap[tool.ToolNumber] = tool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 首先解析原始钻带中的刀具定义行,保存参数信息
|
|
||||||
var originalToolDefinitions = new Dictionary<int, string>();
|
|
||||||
var headerLines = new List<string>();
|
|
||||||
|
|
||||||
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}");
|
|
||||||
|
|
||||||
// 添加该刀具对应的所有坐标数据
|
|
||||||
// HoleLocations现在应该已经保持了原始顺序
|
|
||||||
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");
|
|
||||||
|
|
||||||
// 添加机台码的坐标数据
|
|
||||||
// HoleLocations现在应该已经保持了原始顺序
|
|
||||||
if (tool.HoleLocations != null && tool.HoleLocations.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var location in tool.HoleLocations)
|
|
||||||
{
|
|
||||||
result.Add(location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加结束标记
|
|
||||||
result.Add("M30");
|
|
||||||
|
|
||||||
// 在M30后添加空行,符合标准钻带文件格式
|
|
||||||
return string.Join("\r\n", result) + "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载示例数据
|
/// 加载示例数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1428,34 +1306,7 @@ M30";
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 使用ANSI编码
|
string fileContent = CommandTypeFileReader.ReadAllText(sortFilePath);
|
||||||
Encoding ansiEncoding;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ansiEncoding = Encoding.GetEncoding(936); // 936是GB2312的代码页
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
ansiEncoding = Encoding.Default; // 如果获取失败,使用系统默认编码
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用 cmd 命令读取-sort.txt文件,参考钻带文件读取方法
|
|
||||||
var process = new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "cmd.exe",
|
|
||||||
Arguments = $"/c type \"{sortFilePath}\"",
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
StandardOutputEncoding = ansiEncoding
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
string fileContent = process.StandardOutput.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
// 按行分割内容
|
// 按行分割内容
|
||||||
string[] lines = fileContent.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
string[] lines = fileContent.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
@@ -1953,27 +1804,7 @@ M30";
|
|||||||
throw new System.IO.FileNotFoundException($"参考钻带文件不存在:{referenceFilePath}");
|
throw new System.IO.FileNotFoundException($"参考钻带文件不存在:{referenceFilePath}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用与加载钻带文件相同的方式读取文件内容
|
string drillTapeContent = CommandTypeFileReader.ReadAllText(referenceFilePath);
|
||||||
var process = new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "cmd.exe",
|
|
||||||
Arguments = $"/c type \"{referenceFilePath}\"",
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
string drillTapeContent = process.StandardOutput.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
|
|
||||||
if (process.ExitCode != 0)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"读取参考钻带文件失败,退出代码:{process.ExitCode}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(drillTapeContent))
|
if (string.IsNullOrWhiteSpace(drillTapeContent))
|
||||||
{
|
{
|
||||||
@@ -2401,4 +2232,4 @@ M30";
|
|||||||
return (true, "刀具匹配验证通过", warnings);
|
return (true, "刀具匹配验证通过", warnings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user