feat: 增加3.203孔PP钻带生成逻辑
This commit is contained in:
@@ -46,6 +46,8 @@ namespace DrillTools
|
||||
private const int SvsiEnsureVisible = 0x8;
|
||||
private const int SvsiFocused = 0x10;
|
||||
private const int SelectFileFlags = SvsiSelect | SvsiDeselectOthers | SvsiEnsureVisible | SvsiFocused;
|
||||
private const double PpSourceDiameter = 3.203;
|
||||
private const int PpSideCoordinateTolerance = 1500;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
@@ -1179,27 +1181,20 @@ M30";
|
||||
/// <returns>生成的文件路径</returns>
|
||||
public string GeneratePpDrillTape()
|
||||
{
|
||||
var sourceTool = GetPpSourceTool();
|
||||
if (sourceTool == null)
|
||||
var ppRule = GetPpGenerationRule();
|
||||
if (ppRule == null)
|
||||
throw new InvalidOperationException("当前钻带不满足生成 PP 钻带条件");
|
||||
|
||||
var locations = sourceTool.HoleLocations
|
||||
.Where(location => !string.IsNullOrWhiteSpace(location))
|
||||
.Take(2)
|
||||
.Select(location => location.Trim())
|
||||
.ToList();
|
||||
|
||||
if (locations.Count < 2)
|
||||
throw new InvalidOperationException("3.203 刀具坐标不足,无法生成 PP 钻带");
|
||||
|
||||
string outputFilePath = GetPpDrillTapeOutputPath();
|
||||
var ppDrillTape = new StringBuilder();
|
||||
ppDrillTape.AppendLine("M48");
|
||||
ppDrillTape.AppendLine("T01C4.");
|
||||
ppDrillTape.AppendLine(ppRule.ToolDefinition);
|
||||
ppDrillTape.AppendLine("%");
|
||||
ppDrillTape.AppendLine("T01");
|
||||
ppDrillTape.AppendLine(locations[0]);
|
||||
ppDrillTape.AppendLine(locations[1]);
|
||||
foreach (var location in ppRule.Locations)
|
||||
{
|
||||
ppDrillTape.AppendLine(location);
|
||||
}
|
||||
ppDrillTape.AppendLine("M30");
|
||||
|
||||
File.WriteAllText(outputFilePath, ppDrillTape.ToString(), CreateGb2312Encoding());
|
||||
@@ -1210,16 +1205,28 @@ M30";
|
||||
|
||||
private void UpdatePpDrillTapeState()
|
||||
{
|
||||
CanGeneratePpDrillTape = GetPpSourceTool() != null;
|
||||
CanGeneratePpDrillTape = GetPpGenerationRule() != null;
|
||||
}
|
||||
|
||||
private ToolItem? GetPpSourceTool()
|
||||
private PpGenerationRule? GetPpGenerationRule()
|
||||
{
|
||||
if (!IsStartupDrillTapeFile || !HasOriginalFile || OriginalTools.Count < 2)
|
||||
if (!HasOriginalFile || OriginalTools.Count == 0)
|
||||
return null;
|
||||
|
||||
var legacyRule = GetLegacyPpGenerationRule();
|
||||
if (legacyRule != null)
|
||||
return legacyRule;
|
||||
|
||||
return GetOuterPpGenerationRule();
|
||||
}
|
||||
|
||||
private PpGenerationRule? GetLegacyPpGenerationRule()
|
||||
{
|
||||
if (!IsStartupDrillTapeFile || OriginalTools.Count < 2)
|
||||
return null;
|
||||
|
||||
var sourceTool = OriginalTools[OriginalTools.Count - 2];
|
||||
if (Math.Abs(sourceTool.Diameter - 3.203) >= 0.001)
|
||||
if (Math.Abs(sourceTool.Diameter - PpSourceDiameter) >= 0.001)
|
||||
return null;
|
||||
|
||||
if (sourceTool.TotalHoles != 3)
|
||||
@@ -1228,7 +1235,141 @@ M30";
|
||||
if (sourceTool.HoleLocations == null || sourceTool.HoleLocations.Count < 2)
|
||||
return null;
|
||||
|
||||
return sourceTool;
|
||||
var locations = sourceTool.HoleLocations
|
||||
.Where(location => !string.IsNullOrWhiteSpace(location))
|
||||
.Take(2)
|
||||
.Select(location => location.Trim())
|
||||
.ToList();
|
||||
|
||||
return locations.Count == 2
|
||||
? new PpGenerationRule("T01C4.", locations)
|
||||
: null;
|
||||
}
|
||||
|
||||
private PpGenerationRule? GetOuterPpGenerationRule()
|
||||
{
|
||||
var sourceTool = OriginalTools.FirstOrDefault(tool =>
|
||||
Math.Abs(tool.Diameter - PpSourceDiameter) < 0.001
|
||||
&& (tool.TotalHoles == 13 || tool.TotalHoles == 15)
|
||||
&& tool.HoleLocations != null
|
||||
&& tool.HoleLocations.Count >= 4
|
||||
&& CanSelectPpDrillTapeLocations(tool));
|
||||
|
||||
return sourceTool == null
|
||||
? null
|
||||
: new PpGenerationRule("T01C4.000", SelectPpDrillTapeLocations(sourceTool));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 3.203 外框孔中按右、上、左、下四边各取一个中位孔,并保持原钻带坐标文本。
|
||||
/// </summary>
|
||||
private static List<string> SelectPpDrillTapeLocations(ToolItem sourceTool)
|
||||
{
|
||||
var points = ParsePpHolePoints(sourceTool.HoleLocations);
|
||||
if (points.Count < 4)
|
||||
throw new InvalidOperationException("3.203 刀具坐标不足,无法生成 PP 钻带");
|
||||
|
||||
int minX = points.Min(point => point.X);
|
||||
int maxX = points.Max(point => point.X);
|
||||
int minY = points.Min(point => point.Y);
|
||||
int maxY = points.Max(point => point.Y);
|
||||
|
||||
var selected = new[]
|
||||
{
|
||||
SelectMiddlePoint(points.Where(point => Math.Abs(point.X - maxX) <= PpSideCoordinateTolerance), sortByX: false, useUpperMiddle: true),
|
||||
SelectMiddlePoint(points.Where(point => Math.Abs(point.Y - maxY) <= PpSideCoordinateTolerance), sortByX: true, useUpperMiddle: false),
|
||||
SelectMiddlePoint(points.Where(point => Math.Abs(point.X - minX) <= PpSideCoordinateTolerance), sortByX: false, useUpperMiddle: true),
|
||||
SelectMiddlePoint(points.Where(point => Math.Abs(point.Y - minY) <= PpSideCoordinateTolerance), sortByX: true, useUpperMiddle: false)
|
||||
};
|
||||
|
||||
if (selected.Any(point => point == null))
|
||||
throw new InvalidOperationException("3.203 刀具未形成完整的上下左右四边孔位,无法生成 PP 钻带");
|
||||
|
||||
var selectedTexts = selected
|
||||
.Select(point => point!.Text)
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
if (selectedTexts.Count != 4)
|
||||
throw new InvalidOperationException("3.203 刀具四边中位孔存在重复,无法生成 PP 钻带");
|
||||
|
||||
// 输出顺序沿用原 3.203 刀具中的孔位顺序,避免改变已有钻带坐标排序习惯。
|
||||
return points
|
||||
.Where(point => selectedTexts.Contains(point.Text))
|
||||
.Select(point => point.Text)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static bool CanSelectPpDrillTapeLocations(ToolItem sourceTool)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SelectPpDrillTapeLocations(sourceTool).Count == 4;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<PpHolePoint> ParsePpHolePoints(IEnumerable<string> holeLocations)
|
||||
{
|
||||
var points = new List<PpHolePoint>();
|
||||
foreach (var location in holeLocations)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(location))
|
||||
continue;
|
||||
|
||||
var match = Regex.Match(location.Trim(), @"X([+-]?\d+)Y([+-]?\d+)");
|
||||
if (!match.Success)
|
||||
continue;
|
||||
|
||||
points.Add(new PpHolePoint(
|
||||
location.Trim(),
|
||||
int.Parse(match.Groups[1].Value),
|
||||
int.Parse(match.Groups[2].Value)));
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static PpHolePoint? SelectMiddlePoint(IEnumerable<PpHolePoint> sourcePoints, bool sortByX, bool useUpperMiddle)
|
||||
{
|
||||
var points = sortByX
|
||||
? sourcePoints.OrderBy(point => point.X).ThenBy(point => point.Y).ToList()
|
||||
: sourcePoints.OrderBy(point => point.Y).ThenBy(point => point.X).ToList();
|
||||
|
||||
if (points.Count == 0)
|
||||
return null;
|
||||
|
||||
int index = useUpperMiddle ? points.Count / 2 : (points.Count - 1) / 2;
|
||||
return points[index];
|
||||
}
|
||||
|
||||
private sealed class PpHolePoint
|
||||
{
|
||||
public PpHolePoint(string text, int x, int y)
|
||||
{
|
||||
Text = text;
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public string Text { get; }
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
}
|
||||
|
||||
private sealed class PpGenerationRule
|
||||
{
|
||||
public PpGenerationRule(string toolDefinition, List<string> locations)
|
||||
{
|
||||
ToolDefinition = toolDefinition;
|
||||
Locations = locations;
|
||||
}
|
||||
|
||||
public string ToolDefinition { get; }
|
||||
public List<string> Locations { get; }
|
||||
}
|
||||
|
||||
private string GetPpDrillTapeOutputPath()
|
||||
|
||||
Reference in New Issue
Block a user