Files
AohDrllTools/ExcellonScaler.cs
Mr.Xia cacbbe6c33 feat: 增加钻带涨缩功能,支持倍率/PPM模式缩放坐标
- 新增 ExcellonScaler 引擎:普通孔缩放坐标,G85槽孔保护槽长,刀具定义行原样保留
- 新增 DrillScalingWindow 参数设置窗口:倍率/PPM模式切换,X/Y独立输入
- 集成到启动功能菜单:.dr2/.dpin 文件显示"涨缩"按钮
- 输出覆盖原文件 + .bak 备份,GB2312 编码
2026-06-05 22:17:15 +08:00

155 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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}";
}
}
}