From fa697c9fd0467b7182b5d4624ba73e8080b04472 Mon Sep 17 00:00:00 2001 From: "Mr.Xia" <1424473282@qq.com> Date: Sat, 27 Jun 2026 16:24:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9F=BA=E7=A1=80=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=8F=A0=E6=9D=BF=E8=AE=A1=E7=AE=97=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 StackCountCalculator: 数字化规则表(短槽刀/EA刀10×4、槽刀10×4、钻针10×6),公开Calculate方法,输入校验,查表逻辑,16oz铜厚递减 - 新增 StartupSelectionViewModel: 替换匿名DataContext,保留所有显示属性,新增板厚/铜厚输入、计算结果/明细、CanCalculate - 新增 NonEmptyToVisibilityConverter - 修改 StartupSelectionWindow.xaml: 增宽680px,新增3行(输入+结果+明细),计算按钮在基础信息内部 - 修改 StartupSelectionWindow.xaml.cs: 构造函数接收ViewModel,新增计算按钮事件 - 修改 App.xaml.cs: 构建ViewModel实例,CalculateStackMinDiameters独立遍历Tools(含0.749mm,排除机台码) - 修改 App.xaml: 注册NonEmptyToVisibilityConverter --- App.xaml | 2 + App.xaml.cs | 74 ++++- NonEmptyToVisibilityConverter.cs | 26 ++ StackCountCalculator.cs | 502 +++++++++++++++++++++++++++++++ StartupSelectionViewModel.cs | 266 ++++++++++++++++ StartupSelectionWindow.xaml | 46 ++- StartupSelectionWindow.xaml.cs | 34 +-- 7 files changed, 919 insertions(+), 31 deletions(-) create mode 100644 NonEmptyToVisibilityConverter.cs create mode 100644 StackCountCalculator.cs create mode 100644 StartupSelectionViewModel.cs diff --git a/App.xaml b/App.xaml index 4736da5..4e969c8 100644 --- a/App.xaml +++ b/App.xaml @@ -6,6 +6,8 @@ + + 14 16 diff --git a/App.xaml.cs b/App.xaml.cs index 2c5eb49..5e3e68e 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; using System.Windows; +using System.Collections.ObjectModel; namespace DrillTools { @@ -60,20 +61,28 @@ namespace DrillTools double outer3175XSpacing = viewModel.Outer3175XSpacing; double outer3175YSpacing = viewModel.Outer3175YSpacing; + var selectionViewModel = new StartupSelectionViewModel + { + FileName = Path.GetFileNameWithoutExtension(filePath), + MinDrillDiameter = minDrill, + MinSlotDiameter = minSlot, + MinEADiameter = minEA, + IsPpDrillTape = isPpDrillTape, + PpXSpacing = ppXSpacing, + PpYSpacing = ppYSpacing, + HasOuter3175Spacing = hasOuter3175Spacing, + Outer3175XSpacing = outer3175XSpacing, + Outer3175YSpacing = outer3175YSpacing + }; + + // 叠板计算用的最小刀径独立遍历 Tools 计算,包含 0.749mm + CalculateStackMinDiameters(viewModel.Tools, selectionViewModel); + var selectionWindow = new StartupSelectionWindow( - filePath, + selectionViewModel, canClearParameters, canGeneratePpDrillTape, - canScaleDrillTape, - minDrill, - minSlot, - minEA, - isPpDrillTape, - ppXSpacing, - ppYSpacing, - hasOuter3175Spacing, - outer3175XSpacing, - outer3175YSpacing); + canScaleDrillTape); selectionWindow.ShowDialog(); switch (selectionWindow.SelectedAction) @@ -290,5 +299,48 @@ namespace DrillTools return supportedExtensions.Contains(extension); } + + /// + /// 从 MainWindowViewModel.Tools 独立遍历计算叠板用最小刀径 + /// 分类逻辑与 UpdateMinDiameterInfo 一致,但不排除 0.749mm + /// 槽刀分类映射:Slot/DustSlot/DeburrSlot → 槽刀,EASlot/EASlot2 → EA刀,Drill → 钻针 + /// + private static void CalculateStackMinDiameters( + ObservableCollection tools, + StartupSelectionViewModel selectionViewModel) + { + double minDrill = 0; + double minSlot = 0; + double minEA = 0; + + foreach (var tool in tools) + { + // 机台码刀具(ToolType.MachineCode)是固定孔位,不参与叠板计算 + if (tool.ToolType == ToolType.MachineCode) + continue; + + var category = ToolItem.GetToolCategory(tool.ToolSuffixType); + + switch (category) + { + case ToolCategory.Drill: + if (minDrill == 0 || tool.Diameter < minDrill) + minDrill = tool.Diameter; + break; + case ToolCategory.Slot: + if (minSlot == 0 || tool.Diameter < minSlot) + minSlot = tool.Diameter; + break; + case ToolCategory.EA: + if (minEA == 0 || tool.Diameter < minEA) + minEA = tool.Diameter; + break; + } + } + + selectionViewModel.StackCalcMinDrill = minDrill; + selectionViewModel.StackCalcMinSlot = minSlot; + selectionViewModel.StackCalcMinEA = minEA; + } } } diff --git a/NonEmptyToVisibilityConverter.cs b/NonEmptyToVisibilityConverter.cs new file mode 100644 index 0000000..83cfc4a --- /dev/null +++ b/NonEmptyToVisibilityConverter.cs @@ -0,0 +1,26 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace DrillTools +{ + /// + /// 非空字符串到可见性转换器 + /// 非空且非空白字符串 → Visible,否则 → Collapsed + /// + public class NonEmptyToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is string s && !string.IsNullOrWhiteSpace(s)) + return Visibility.Visible; + return Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + } +} diff --git a/StackCountCalculator.cs b/StackCountCalculator.cs new file mode 100644 index 0000000..d707aff --- /dev/null +++ b/StackCountCalculator.cs @@ -0,0 +1,502 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DrillTools +{ + /// + /// 叠板计算结果 + /// + public class StackCountResult + { + /// + /// 是否计算成功 + /// + public bool Success { get; set; } + + /// + /// 建议叠板数(失败时为 0) + /// + public int RecommendedCount { get; set; } + + /// + /// 钻咀叠板数(不存在时为 null,查表失败时为 -1) + /// + public int? DrillCount { get; set; } + + /// + /// 槽刀叠板数(不存在时为 null,查表失败时为 -1) + /// + public int? SlotCount { get; set; } + + /// + /// EA刀叠板数(不存在时为 null,查表失败时为 -1) + /// + public int? EACount { get; set; } + + /// + /// 铜厚递减前的原始最小叠板数(-1 表示无法计算) + /// + public int RawMinCount { get; set; } + + /// + /// 铜厚递减后的叠板数(-1 表示无法计算) + /// + public int AfterCopperReduction { get; set; } + + /// + /// 限制原因或错误信息 + /// + public string Message { get; set; } = string.Empty; + + /// + /// 各类别明细描述 + /// + public string Detail { get; set; } = string.Empty; + } + + /// + /// 钻孔叠板参数计算器 + /// 规则来源:《钻孔叠板参数表》(1009B-2013钻机参数表 D2-f A1A2厂) + /// + public static class StackCountCalculator + { + #region 规则表常量 + + /// + /// 板厚总范围下限(mm) + /// + private const double BoardThicknessMin = 0.4; + + /// + /// 板厚总范围上限(mm) + /// + private const double BoardThicknessMax = 3.4; + + /// + /// 16oz 总铜厚限制 + /// + private const double MaxTotalCopperOz = 16.0; + + /// + /// 板厚行定义:(下限, 上限),左闭右开,最后一行左闭右闭 + /// + private static readonly (double Lo, double Hi)[] BoardThicknessRows = + { + (0.40, 0.65), + (0.66, 0.85), + (0.86, 0.95), + (0.96, 1.05), + (1.06, 1.15), + (1.16, 1.35), + (1.36, 1.65), + (1.66, 2.05), + (2.06, 2.55), + (2.56, 3.40) + }; + + /// + /// 短槽刀 / EA 刀规则表(10行×4列) + /// 列顺序:D=0.60, D=0.65, D=0.70, D>=0.75 + /// -1 表示 "/" 或 "-"(无法达到) + /// + private static readonly int?[,] EAOrShortSlotTable = + { + // D=0.60 D=0.65 D=0.70 D>=0.75 + { 5, 5, 5, 5 }, // 0.40-0.65 + { 4, 4, 5, 5 }, // 0.66-0.85 + { 3, 4, 5, 5 }, // 0.86-0.95 + { 3, 3, 4, 4 }, // 0.96-1.05 + { 3, 3, 4, 4 }, // 1.06-1.15 + { 2, 3, 4, 4 }, // 1.16-1.35 + { 2, 2, 3, 3 }, // 1.36-1.65 + { 1, 2, 2, 2 }, // 1.66-2.05 + { 1, 1, 1, 1 }, // 2.06-2.55 + { 1, 1, 1, 1 } // 2.56-3.40 + }; + + /// + /// 槽刀规则表(10行×4列) + /// 列顺序:D=0.50, D=0.55, D=0.60-0.65, D>=0.70 + /// null 表示 "-"(无法达到) + /// + private static readonly int?[,] SlotTable = + { + // D=0.50 D=0.55 D=0.60-0.65 D>=0.70 + { 5, 5, 5, null }, // 0.40-0.65 + { 5, 5, 5, 5 }, // 0.66-0.85 + { 5, 5, 5, 5 }, // 0.86-0.95 + { 4, 5, 5, 5 }, // 0.96-1.05 + { 3, 4, 4, 5 }, // 1.06-1.15 + { 3, 4, 4, 5 }, // 1.16-1.35 + { 2, 3, 3, 4 }, // 1.36-1.65 + { 2, 2, 2, 3 }, // 1.66-2.05 + { 1, 2, 2, 2 }, // 2.06-2.55 + { 1, 1, 1, 2 } // 2.56-3.40 + }; + + /// + /// 钻针规则表(10行×6列) + /// 列顺序:D=0.20-0.225, D=0.25, D=0.275-0.30, D=0.35-0.40, D=0.45, D>=0.50 + /// + private static readonly int?[,] DrillTable = + { + // D=0.20-0.225 D=0.25 D=0.275-0.30 D=0.35-0.40 D=0.45 D>=0.50 + { 5, 5, 5, 5, 5, 5 }, // 0.40-0.65 + { 4, 5, 5, 5, 5, 5 }, // 0.66-0.85 + { 3, 5, 5, 5, 5, 5 }, // 0.86-0.95 + { 3, 5, 5, 5, 5, 5 }, // 0.96-1.05 + { 2, 4, 4, 4, 5, 5 }, // 1.06-1.15 + { 2, 3, 3, 4, 4, 5 }, // 1.16-1.35 + { 2, 3, 3, 3, 3, 4 }, // 1.36-1.65 + { 1, 2, 2, 2, 2, 3 }, // 1.66-2.05 + { 1, 2, 2, 2, 2, 2 }, // 2.06-2.55 + { 1, 1, 1, 1, 1, 2 } // 2.56-3.40 + }; + + #endregion + + #region 公开方法 + + /// + /// 计算建议叠板数 + /// + /// 板厚(mm) + /// 单张板总铜厚(oz) + /// 最小钻针直径(0 表示钻带中无钻针) + /// 最小槽刀直径(0 表示钻带中无槽刀) + /// 最小EA刀直径(0 表示钻带中无EA刀) + /// 叠板计算结果 + public static StackCountResult Calculate( + double boardThickness, double copperThickness, + double minDrill, double minSlot, double minEA) + { + // 1. 输入校验 + string? validationError = ValidateInputs(boardThickness, copperThickness, minDrill, minSlot, minEA); + if (validationError != null) + { + return new StackCountResult + { + Success = false, + Message = validationError + }; + } + + // 2. 判断各类刀具是否存在 + bool hasDrill = minDrill > 0; + bool hasSlot = minSlot > 0; + bool hasEA = minEA > 0; + + // 三类都不存在则无法计算 + if (!hasDrill && !hasSlot && !hasEA) + { + return new StackCountResult + { + Success = false, + Message = "当前钻带中不存在钻针、槽刀和EA刀,无法计算叠板数" + }; + } + + // 3. 查板厚行 + int rowIdx = FindBoardThicknessRowIndex(boardThickness); + if (rowIdx < 0) + { + return new StackCountResult + { + Success = false, + Message = $"板厚 {boardThickness}mm 不在规则表范围({BoardThicknessMin}-{BoardThicknessMax}mm)内" + }; + } + + // 4. 各类分别查表 + var detailParts = new List(); + int? drillResult = null; + int? slotResult = null; + int? eaResult = null; + string? drillFailReason = null; + string? slotFailReason = null; + string? eaFailReason = null; + + if (hasDrill) + { + var (count, reason) = LookupDrillTable(rowIdx, minDrill); + drillResult = count; + drillFailReason = reason; + } + + if (hasSlot) + { + var (count, reason) = LookupSlotTable(rowIdx, minSlot); + slotResult = count; + slotFailReason = reason; + } + + if (hasEA) + { + var (count, reason) = LookupEATable(rowIdx, minEA); + eaResult = count; + eaFailReason = reason; + } + + // 5. 构建各类明细 + // 存在但查表失败的类别使整体无法计算 + bool anyExistingCategoryFailed = false; + + if (!hasDrill) + { + drillResult = null; + detailParts.Add("钻针 无"); + } + else if (drillResult == null || drillResult < 0) + { + anyExistingCategoryFailed = true; + detailParts.Add($"钻针 查表失败({drillFailReason})"); + } + else + { + detailParts.Add($"钻针 {drillResult}"); + } + + if (!hasSlot) + { + slotResult = null; + detailParts.Add("槽刀 无"); + } + else if (slotResult == null || slotResult < 0) + { + anyExistingCategoryFailed = true; + detailParts.Add($"槽刀 查表失败({slotFailReason})"); + } + else + { + detailParts.Add($"槽刀 {slotResult}"); + } + + if (!hasEA) + { + eaResult = null; + detailParts.Add("EA刀 无"); + } + else if (eaResult == null || eaResult < 0) + { + anyExistingCategoryFailed = true; + detailParts.Add($"EA刀 查表失败({eaFailReason})"); + } + else + { + detailParts.Add($"EA刀 {eaResult}"); + } + + // 6. 存在但失败的类别使整体标记为无法计算 + if (anyExistingCategoryFailed) + { + return new StackCountResult + { + Success = false, + DrillCount = hasDrill ? drillResult : null, + SlotCount = hasSlot ? slotResult : null, + EACount = hasEA ? eaResult : null, + Message = "存在无法匹配规则的刀具类别,无法计算叠板数", + Detail = string.Join(" / ", detailParts) + }; + } + + // 7. 取存在且成功的类别中的最小值 + var validCounts = new List(); + if (hasDrill && drillResult.HasValue && drillResult.Value > 0) + validCounts.Add(drillResult.Value); + if (hasSlot && slotResult.HasValue && slotResult.Value > 0) + validCounts.Add(slotResult.Value); + if (hasEA && eaResult.HasValue && eaResult.Value > 0) + validCounts.Add(eaResult.Value); + + int rawMin = validCounts.Min(); + + // 8. 套用 16oz 总铜厚递减限制 + int afterCopper = ApplyCopperReduction(rawMin, copperThickness); + + // 9. 构建结果明细 + string copperNote = afterCopper < rawMin + ? $"铜厚限制({copperThickness}oz×{rawMin}张={copperThickness * rawMin}oz > {MaxTotalCopperOz}oz),递减至 {afterCopper} 张" + : "铜厚通过"; + detailParts.Add(copperNote); + detailParts.Add($"最终取 {afterCopper} 张"); + + return new StackCountResult + { + Success = true, + RecommendedCount = afterCopper, + DrillCount = hasDrill ? drillResult : null, + SlotCount = hasSlot ? slotResult : null, + EACount = hasEA ? eaResult : null, + RawMinCount = rawMin, + AfterCopperReduction = afterCopper, + Detail = string.Join(" / ", detailParts) + }; + } + + #endregion + + #region 输入校验 + + /// + /// 校验输入参数,返回 null 表示通过,否则返回中文错误提示 + /// + private static string? ValidateInputs(double boardThickness, double copperThickness, + double minDrill, double minSlot, double minEA) + { + // 板厚校验 + if (double.IsNaN(boardThickness) || boardThickness <= 0) + return "请输入有效的板厚(必须为大于0的数字)"; + + if (boardThickness < BoardThicknessMin || boardThickness > BoardThicknessMax) + return $"板厚 {boardThickness}mm 不在规则表范围({BoardThicknessMin}-{BoardThicknessMax}mm)内"; + + // 铜厚校验 + if (double.IsNaN(copperThickness) || copperThickness <= 0) + return "请输入有效的铜厚(必须为大于0的数字)"; + + // 各类刀径校验:非 NaN、不为负 + if (double.IsNaN(minDrill) || minDrill < 0) + return "钻针最小直径数据异常"; + if (double.IsNaN(minSlot) || minSlot < 0) + return "槽刀最小直径数据异常"; + if (double.IsNaN(minEA) || minEA < 0) + return "EA刀最小直径数据异常"; + + return null; + } + + #endregion + + #region 板厚行查找 + + /// + /// 查找板厚对应的行索引 + /// 行区间按 PRD 定义紧密衔接(如 0.40-0.65 / 0.66-0.85),使用精确比较 + /// + /// 板厚 + /// 行索引,-1 表示未找到 + private static int FindBoardThicknessRowIndex(double boardThickness) + { + for (int i = 0; i < BoardThicknessRows.Length; i++) + { + var (lo, hi) = BoardThicknessRows[i]; + // 使用 0.001 容差处理浮点精度(如 0.6600001 应落入 0.66-0.85 行) + const double eps = 0.001; + if (boardThickness >= lo - eps && boardThickness <= hi + eps) + return i; + } + return -1; + } + + #endregion + + #region 列匹配与查表 + + /// + /// 短槽刀/EA刀列匹配 + /// 列定义:D=0.60, D=0.65, D=0.70, D>=0.75 + /// + private static int FindEAColumnIndex(double diameter) + { + const double eps = 0.001; + if (Math.Abs(diameter - 0.60) < eps) return 0; + if (Math.Abs(diameter - 0.65) < eps) return 1; + if (Math.Abs(diameter - 0.70) < eps) return 2; + if (diameter >= 0.75 - eps) return 3; + return -1; + } + + /// + /// 槽刀列匹配 + /// 列定义:D=0.50, D=0.55, D=0.60-0.65, D>=0.70 + /// + private static int FindSlotColumnIndex(double diameter) + { + const double eps = 0.001; + if (Math.Abs(diameter - 0.50) < eps) return 0; + if (Math.Abs(diameter - 0.55) < eps) return 1; + if (diameter >= 0.60 - eps && diameter <= 0.65 + eps) return 2; + if (diameter >= 0.70 - eps) return 3; + return -1; + } + + /// + /// 钻针列匹配 + /// 列定义:D=0.20-0.225, D=0.25, D=0.275-0.30, D=0.35-0.40, D=0.45, D>=0.50 + /// + private static int FindDrillColumnIndex(double diameter) + { + const double eps = 0.001; + if (diameter >= 0.20 - eps && diameter <= 0.225 + eps) return 0; + if (Math.Abs(diameter - 0.25) < eps) return 1; + if (diameter >= 0.275 - eps && diameter <= 0.30 + eps) return 2; + if (diameter >= 0.35 - eps && diameter <= 0.40 + eps) return 3; + if (Math.Abs(diameter - 0.45) < eps) return 4; + if (diameter >= 0.50 - eps) return 5; + return -1; + } + + /// + /// 通用查表:根据行和列索引读取规则表值 + /// + private static (int? count, string? failReason) LookupTable(int?[,] table, int rowIdx, int colIdx, string toolTypeName) + { + if (colIdx < 0) + { + return (null, $"刀具直径无对应列"); + } + + int? value = table[rowIdx, colIdx]; + if (value == null) + { + return (null, "规则格为 / 或 -,加工能力无法达到"); + } + + return (value, null); + } + + #endregion + + #region 各类查表入口 + + private static (int? count, string? failReason) LookupEATable(int rowIdx, double diameter) + { + int colIdx = FindEAColumnIndex(diameter); + return LookupTable(EAOrShortSlotTable, rowIdx, colIdx, "EA刀"); + } + + private static (int? count, string? failReason) LookupSlotTable(int rowIdx, double diameter) + { + int colIdx = FindSlotColumnIndex(diameter); + return LookupTable(SlotTable, rowIdx, colIdx, "槽刀"); + } + + private static (int? count, string? failReason) LookupDrillTable(int rowIdx, double diameter) + { + int colIdx = FindDrillColumnIndex(diameter); + return LookupTable(DrillTable, rowIdx, colIdx, "钻针"); + } + + #endregion + + #region 铜厚递减逻辑 + + /// + /// 套用 16oz 总铜厚递减限制 + /// 每次减1至总铜厚不超过 16oz 或保留1张 + /// + private static int ApplyCopperReduction(int candidateCount, double singleCopperOz) + { + int count = candidateCount; + while (count > 1 && singleCopperOz * count > MaxTotalCopperOz) + { + count--; + } + return count; + } + + #endregion + } +} diff --git a/StartupSelectionViewModel.cs b/StartupSelectionViewModel.cs new file mode 100644 index 0000000..dc68537 --- /dev/null +++ b/StartupSelectionViewModel.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace DrillTools +{ + /// + /// 启动选择窗口的 ViewModel,承载基础信息显示和叠板计算 + /// + public class StartupSelectionViewModel : INotifyPropertyChanged + { + #region 现有显示属性 + + private string _fileName = string.Empty; + /// + /// 文件名(不含扩展名) + /// + public string FileName + { + get => _fileName; + set => SetProperty(ref _fileName, value); + } + + private double _minDrillDiameter; + /// + /// 最小钻咀直径(显示用,已排除 0.749mm) + /// + public double MinDrillDiameter + { + get => _minDrillDiameter; + set => SetProperty(ref _minDrillDiameter, value); + } + + private double _minSlotDiameter; + /// + /// 最小槽刀直径(显示用) + /// + public double MinSlotDiameter + { + get => _minSlotDiameter; + set => SetProperty(ref _minSlotDiameter, value); + } + + private double _minEADiameter; + /// + /// 最小EA刀直径(显示用) + /// + public double MinEADiameter + { + get => _minEADiameter; + set => SetProperty(ref _minEADiameter, value); + } + + private bool _isPpDrillTape; + /// + /// 是否为 PP 钻带 + /// + public bool IsPpDrillTape + { + get => _isPpDrillTape; + set => SetProperty(ref _isPpDrillTape, value); + } + + private double _ppXSpacing; + /// + /// PP X 间距 + /// + public double PpXSpacing + { + get => _ppXSpacing; + set => SetProperty(ref _ppXSpacing, value); + } + + private double _ppYSpacing; + /// + /// PP Y 间距 + /// + public double PpYSpacing + { + get => _ppYSpacing; + set => SetProperty(ref _ppYSpacing, value); + } + + private bool _hasOuter3175Spacing; + /// + /// 是否有 3.175 外围孔间距 + /// + public bool HasOuter3175Spacing + { + get => _hasOuter3175Spacing; + set => SetProperty(ref _hasOuter3175Spacing, value); + } + + private double _outer3175XSpacing; + /// + /// 3.175 外围孔 X 间距 + /// + public double Outer3175XSpacing + { + get => _outer3175XSpacing; + set => SetProperty(ref _outer3175XSpacing, value); + } + + private double _outer3175YSpacing; + /// + /// 3.175 外围孔 Y 间距 + /// + public double Outer3175YSpacing + { + get => _outer3175YSpacing; + set => SetProperty(ref _outer3175YSpacing, value); + } + + #endregion + + #region 新增叠板计算属性 + + private string _boardThicknessInput = string.Empty; + /// + /// 板厚输入(原始文本) + /// + public string BoardThicknessInput + { + get => _boardThicknessInput; + set + { + if (SetProperty(ref _boardThicknessInput, value)) + UpdateCanCalculate(); + } + } + + private string _copperThicknessInput = string.Empty; + /// + /// 铜厚输入(原始文本,单位 oz) + /// + public string CopperThicknessInput + { + get => _copperThicknessInput; + set + { + if (SetProperty(ref _copperThicknessInput, value)) + UpdateCanCalculate(); + } + } + + private string _stackCountResult = string.Empty; + /// + /// 叠板计算结果文本(如"建议叠板:4 张"或错误提示) + /// + public string StackCountResult + { + get => _stackCountResult; + set => SetProperty(ref _stackCountResult, value); + } + + private string _stackCountDetail = string.Empty; + /// + /// 叠板计算明细文本 + /// + public string StackCountDetail + { + get => _stackCountDetail; + set => SetProperty(ref _stackCountDetail, value); + } + + private bool _canCalculate; + /// + /// 是否可以执行计算(板厚和铜厚都已输入有效数字) + /// + public bool CanCalculate + { + get => _canCalculate; + set => SetProperty(ref _canCalculate, value); + } + + #endregion + + #region 叠板计算用最小刀径(不排除 0.749mm) + + /// + /// 叠板计算用的最小钻针直径(包含 0.749mm,由调用方遍历 Tools 独立计算) + /// + public double StackCalcMinDrill { get; set; } + + /// + /// 叠板计算用的最小槽刀直径(包含 0.749mm 的槽刀,由调用方独立计算) + /// + public double StackCalcMinSlot { get; set; } + + /// + /// 叠板计算用的最小EA刀直径(由调用方独立计算) + /// + public double StackCalcMinEA { get; set; } + + #endregion + + #region 计算方法 + + /// + /// 执行叠板计算(由按钮点击转调) + /// + public void CalculateStackCount() + { + // 解析输入 + if (!double.TryParse(BoardThicknessInput, out double boardThickness) || + !double.TryParse(CopperThicknessInput, out double copperThickness)) + { + StackCountResult = "请输入有效的板厚和铜厚数字"; + StackCountDetail = string.Empty; + return; + } + + // 调用计算器 + var result = StackCountCalculator.Calculate( + boardThickness, copperThickness, + StackCalcMinDrill, StackCalcMinSlot, StackCalcMinEA); + + if (result.Success) + { + StackCountResult = $"建议叠板:{result.RecommendedCount} 张"; + StackCountDetail = result.Detail; + } + else + { + StackCountResult = "无法计算"; + StackCountDetail = string.IsNullOrEmpty(result.Detail) + ? result.Message + : $"{result.Message}\n{result.Detail}"; + } + } + + /// + /// 更新 CanCalculate 状态(板厚和铜厚均为大于 0 的数字时可用) + /// + private void UpdateCanCalculate() + { + CanCalculate = double.TryParse(BoardThicknessInput, out double bt) && bt > 0 && + double.TryParse(CopperThicknessInput, out double ct) && ct > 0; + } + + #endregion + + #region INotifyPropertyChanged + + public event PropertyChangedEventHandler? PropertyChanged; + + protected bool SetProperty(ref T field, T value, [CallerMemberName] string? propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) + return false; + + field = value; + OnPropertyChanged(propertyName); + return true; + } + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + } +} diff --git a/StartupSelectionWindow.xaml b/StartupSelectionWindow.xaml index e3a0190..02fdb97 100644 --- a/StartupSelectionWindow.xaml +++ b/StartupSelectionWindow.xaml @@ -2,7 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="选择功能" - Width="570" + Width="680" SizeToContent="Height" ResizeMode="NoResize" Topmost="True" @@ -21,6 +21,9 @@ + + + @@ -88,6 +91,47 @@ VerticalAlignment="Center" Text="{Binding Outer3175YSpacing, StringFormat=Y间距: {0:F3}}" /> + + + + + + + + + + + + + + + + +