Files
AohDrllTools/ExcellonScaler.cs

169 lines
6.2 KiB
C#
Raw Permalink 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.Globalization;
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{FormatCoordinateValue(xNew)}Y{FormatCoordinateValue(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{FormatCoordinateValue(newStartX)}Y{FormatCoordinateValue(newStartY)}" +
$"G85X{FormatCoordinateValue(newEndX)}Y{FormatCoordinateValue(newEndY)}";
}
/// <summary>
/// 将坐标数值格式化为钻带使用的 6 位坐标文本,负数保留负号。
/// </summary>
private static string FormatCoordinateValue(long value)
{
if (value < 0)
return "-" + Math.Abs(value).ToString("D6", CultureInfo.InvariantCulture);
return value.ToString("D6", CultureInfo.InvariantCulture);
}
}
}