- 新增 ExcellonScaler 引擎:普通孔缩放坐标,G85槽孔保护槽长,刀具定义行原样保留 - 新增 DrillScalingWindow 参数设置窗口:倍率/PPM模式切换,X/Y独立输入 - 集成到启动功能菜单:.dr2/.dpin 文件显示"涨缩"按钮 - 输出覆盖原文件 + .bak 备份,GB2312 编码
155 lines
5.6 KiB
C#
155 lines
5.6 KiB
C#
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}";
|
||
}
|
||
}
|
||
}
|