feat: 增加钻带涨缩功能,支持倍率/PPM模式缩放坐标
- 新增 ExcellonScaler 引擎:普通孔缩放坐标,G85槽孔保护槽长,刀具定义行原样保留 - 新增 DrillScalingWindow 参数设置窗口:倍率/PPM模式切换,X/Y独立输入 - 集成到启动功能菜单:.dr2/.dpin 文件显示"涨缩"按钮 - 输出覆盖原文件 + .bak 备份,GB2312 编码
This commit is contained in:
154
ExcellonScaler.cs
Normal file
154
ExcellonScaler.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace DrillTools.Integration
|
||||
{
|
||||
/// <summary>
|
||||
/// Excellon 钻带涨缩引擎
|
||||
/// 对钻孔坐标进行 X/Y 方向独立缩放,保持槽孔长度不变
|
||||
/// </summary>
|
||||
internal static class ExcellonScaler
|
||||
{
|
||||
// 坐标模式:X 后跟可选符号的数字(可能含小数点),Y 同理
|
||||
private static readonly Regex CoordinatePattern = new(
|
||||
@"^X([+-]?\d+\.?\d*)Y([+-]?\d+\.?\d*)$",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
// G85 槽孔模式:X...Y...G85X...Y...
|
||||
private static readonly Regex SlotPattern = new(
|
||||
@"^(X[+-]?\d+\.?\d*Y[+-]?\d+\.?\d*)G85(X[+-]?\d+\.?\d*Y[+-]?\d+\.?\d*)$",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
// 解析 X 或 Y 坐标值的子模式
|
||||
private static readonly Regex XValuePattern = new(
|
||||
@"X([+-]?\d+\.?\d*)", RegexOptions.Compiled);
|
||||
private static readonly Regex YValuePattern = new(
|
||||
@"Y([+-]?\d+\.?\d*)", RegexOptions.Compiled);
|
||||
|
||||
// 刀具定义行模式(在头部,如 T01C0.799H05000Z+0.000S060.00)
|
||||
private static readonly Regex ToolDefinitionPattern = new(
|
||||
@"^T\d+C", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// 对钻带内容执行涨缩
|
||||
/// </summary>
|
||||
/// <param name="content">原始钻带内容</param>
|
||||
/// <param name="kx">X 方向缩放倍率</param>
|
||||
/// <param name="ky">Y 方向缩放倍率</param>
|
||||
/// <returns>缩放后的钻带内容</returns>
|
||||
public static string Scale(string content, double kx, double ky)
|
||||
{
|
||||
if (content == null)
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
|
||||
var lines = content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
||||
var result = new List<string>(lines.Length);
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
string trimmed = line.Trim();
|
||||
|
||||
// 空行直接保留
|
||||
if (string.IsNullOrEmpty(trimmed))
|
||||
{
|
||||
result.Add(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 刀具定义行(TxxC...):严格原样保留
|
||||
if (ToolDefinitionPattern.IsMatch(trimmed))
|
||||
{
|
||||
result.Add(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// G85 槽孔行:缩放中心点,保持槽长不变
|
||||
var slotMatch = SlotPattern.Match(trimmed);
|
||||
if (slotMatch.Success)
|
||||
{
|
||||
result.Add(ScaleSlotLine(trimmed, kx, ky));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 普通坐标行:X...Y...
|
||||
var coordMatch = CoordinatePattern.Match(trimmed);
|
||||
if (coordMatch.Success)
|
||||
{
|
||||
result.Add(ScaleCoordinateLine(trimmed, kx, ky));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 其余行原样保留(M48, %, Txx, M30 等)
|
||||
result.Add(line);
|
||||
}
|
||||
|
||||
return string.Join("\r\n", result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缩放普通坐标行
|
||||
/// </summary>
|
||||
private static string ScaleCoordinateLine(string line, double kx, double ky)
|
||||
{
|
||||
var xMatch = XValuePattern.Match(line);
|
||||
var yMatch = YValuePattern.Match(line);
|
||||
|
||||
if (!xMatch.Success || !yMatch.Success)
|
||||
return line;
|
||||
|
||||
double xOrig = double.Parse(xMatch.Groups[1].Value);
|
||||
double yOrig = double.Parse(yMatch.Groups[1].Value);
|
||||
|
||||
long xNew = (long)Math.Round(xOrig * kx);
|
||||
long yNew = (long)Math.Round(yOrig * ky);
|
||||
|
||||
return $"X{xNew}Y{yNew}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缩放 G85 槽孔行
|
||||
/// 缩放中心点,保持原始矢量恢复起止点(槽长不变)
|
||||
/// </summary>
|
||||
private static string ScaleSlotLine(string line, double kx, double ky)
|
||||
{
|
||||
var slotMatch = SlotPattern.Match(line);
|
||||
if (!slotMatch.Success)
|
||||
return line;
|
||||
|
||||
// 解析起点坐标
|
||||
var startPart = slotMatch.Groups[1].Value;
|
||||
var xStartMatch = XValuePattern.Match(startPart);
|
||||
var yStartMatch = YValuePattern.Match(startPart);
|
||||
double xStart = double.Parse(xStartMatch.Groups[1].Value);
|
||||
double yStart = double.Parse(yStartMatch.Groups[1].Value);
|
||||
|
||||
// 解析终点坐标
|
||||
var endPart = slotMatch.Groups[2].Value;
|
||||
var xEndMatch = XValuePattern.Match(endPart);
|
||||
var yEndMatch = YValuePattern.Match(endPart);
|
||||
double xEnd = double.Parse(xEndMatch.Groups[1].Value);
|
||||
double yEnd = double.Parse(yEndMatch.Groups[1].Value);
|
||||
|
||||
// 计算中心点
|
||||
double cx = (xStart + xEnd) / 2.0;
|
||||
double cy = (yStart + yEnd) / 2.0;
|
||||
|
||||
// 缩放中心点
|
||||
long cxNew = (long)Math.Round(cx * kx);
|
||||
long cyNew = (long)Math.Round(cy * ky);
|
||||
|
||||
// 保持原始矢量(槽长不变)
|
||||
long dx = (long)Math.Round((xEnd - xStart) / 2.0);
|
||||
long dy = (long)Math.Round((yEnd - yStart) / 2.0);
|
||||
|
||||
// 恢复起止点
|
||||
long newStartX = cxNew - dx;
|
||||
long newStartY = cyNew - dy;
|
||||
long newEndX = cxNew + dx;
|
||||
long newEndY = cyNew + dy;
|
||||
|
||||
return $"X{newStartX}Y{newStartY}G85X{newEndX}Y{newEndY}";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user