using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace DrillTools { /// /// 二维点结构 /// public struct Point2D { public double X { get; set; } public double Y { get; set; } public string OriginalString { get; set; } // 存储原始坐标字符串 public Point2D(double x, double y) { X = x; Y = y; OriginalString = ""; } public Point2D(double x, double y, string originalString) { X = x; Y = y; OriginalString = originalString; } /// /// 从钻带坐标字符串创建点(格式:X+/-数字Y+/-数字) /// public static Point2D ParseFromDrillString(string drillString) { var pattern = @"X([+-]?\d+\.?\d*)Y([+-]?\d+\.?\d*)"; var match = Regex.Match(drillString, pattern); if (match.Success) { double x = double.Parse(match.Groups[1].Value) / 1000.0; // 转换为mm double y = double.Parse(match.Groups[2].Value) / 1000.0; // 转换为mm return new Point2D(x, y, drillString); // 保存原始字符串 } throw new ArgumentException($"无效的钻带坐标格式: {drillString}"); } public static Point2D operator +(Point2D p1, Point2D p2) => new Point2D(p1.X + p2.X, p1.Y + p2.Y); public static Point2D operator -(Point2D p1, Point2D p2) => new Point2D(p1.X - p2.X, p1.Y - p2.Y); } /// /// 线段槽孔结构 /// public struct LineSlot { public Point2D StartPoint { get; set; } public Point2D EndPoint { get; set; } public double Width { get; set; } // 槽孔宽度/孔径(单位:mm) public LineSlot(Point2D startPoint, Point2D endPoint, double width) { StartPoint = startPoint; EndPoint = endPoint; Width = width; } /// /// 获取槽孔长度 /// public double Length => Math.Sqrt(Math.Pow(StartPoint.X - EndPoint.X, 2) + Math.Pow(StartPoint.Y - EndPoint.Y, 2)); } /// /// 弧段槽孔结构 /// public struct ArcSlot { public Point2D StartPoint { get; set; } public Point2D EndPoint { get; set; } public Point2D CenterPoint { get; set; } public double Width { get; set; } // 槽孔宽度/孔径(单位:mm) public bool CounterClockwise { get; set; } // 是否逆时针方向 public ArcSlot(Point2D startPoint, Point2D endPoint, Point2D centerPoint, double width, bool counterClockwise = false) { StartPoint = startPoint; EndPoint = endPoint; CenterPoint = centerPoint; Width = width; CounterClockwise = counterClockwise; } /// /// 获取弧段半径 /// public double Radius => Math.Sqrt(Math.Pow(StartPoint.X - CenterPoint.X, 2) + Math.Pow(StartPoint.Y - CenterPoint.Y, 2)); } /// /// 槽孔钻孔数量计算工具类 /// 提供与CAM350一致的槽孔孔数计算方法 /// public static class SlotHoleCalculator { /// /// 默认凸位高度值(CAM350标准,单位:mm) /// private const double DEFAULT_TOLERANCE = 0.0127; /// /// 计算线段槽孔的钻孔数量 /// /// 线段槽孔参数 /// 凸位高度值,默认为0.0127mm(CAM350标准) /// 需要的钻孔数量 public static int CalculateLineSlotHoleCount(LineSlot slot, double tolerance = DEFAULT_TOLERANCE) { // 计算孔半径 double radius = slot.Width / 2.0; // 计算槽孔长度 double slotLength = slot.Length; // 计算孔中心距 double holeCenterDistance = CalculateHoleCenterDistance(radius, tolerance); // 计算孔数 int holeCount = (int)Math.Abs(Math.Floor(-slotLength / holeCenterDistance)) + 1; return holeCount; } /// /// 计算弧段槽孔的钻孔数量 /// /// 弧段槽孔参数 /// 凸位高度值,默认为0.0127mm(CAM350标准) /// 需要的钻孔数量 public static int CalculateArcSlotHoleCount(ArcSlot slot, double tolerance = DEFAULT_TOLERANCE) { // 计算孔半径 double radius = slot.Width / 2.0; // 计算弧段长度 double arcLength = CalculateArcLength(slot); // 计算孔中心距 double holeCenterDistance = CalculateHoleCenterDistance(radius, tolerance); // 计算孔数 int holeCount = (int)Math.Abs(Math.Floor(-arcLength / holeCenterDistance)) + 1; return holeCount; } /// /// 计算线段槽孔的钻孔位置 /// /// 线段槽孔参数 /// 凸位高度值,默认为0.0127mm(CAM350标准) /// 钻孔位置列表 public static List CalculateLineSlotHolePositions(LineSlot slot, double tolerance = DEFAULT_TOLERANCE) { List positions = new List(); // 计算孔半径 double radius = slot.Width / 2.0; // 计算孔中心距 double holeCenterDistance = CalculateHoleCenterDistance(radius, tolerance); // 计算槽孔长度 double slotLength = slot.Length; // 计算孔数 int holeCount = CalculateLineSlotHoleCount(slot, tolerance); // 计算方位角 double angle = CalculateAngle(slot.StartPoint, slot.EndPoint); // 添加起点 positions.Add(slot.StartPoint); // 计算中间点 if (holeCount > 2) { double avgDistance = slotLength / (holeCount - 1); Point2D currentPoint = slot.StartPoint; for (int i = 1; i < holeCount - 1; i++) { currentPoint = CalculateNextPoint(currentPoint, avgDistance, angle); positions.Add(currentPoint); } } // 添加终点 if (holeCount > 1) { positions.Add(slot.EndPoint); } return positions; } /// /// 计算弧段槽孔的钻孔位置 /// /// 弧段槽孔参数 /// 凸位高度值,默认为0.0127mm(CAM350标准) /// 钻孔位置列表 public static List CalculateArcSlotHolePositions(ArcSlot slot, double tolerance = DEFAULT_TOLERANCE) { List positions = new List(); // 计算孔半径 double radius = slot.Width / 2.0; // 计算孔中心距 double holeCenterDistance = CalculateHoleCenterDistance(radius, tolerance); // 计算弧段半径 double arcRadius = slot.Radius; // 计算弧段圆心角 double arcAngle = CalculateArcAngle(slot); // 计算孔数 int holeCount = CalculateArcSlotHoleCount(slot, tolerance); // 计算角度步长 double angleStep = arcAngle / (holeCount - 1); // 计算起始角度 double startAngle = CalculateAngle(slot.CenterPoint, slot.StartPoint); // 添加起点 positions.Add(slot.StartPoint); // 计算中间点 if (holeCount > 2) { double currentAngle = startAngle; if (slot.CounterClockwise) { currentAngle -= angleStep; } else { currentAngle += angleStep; } for (int i = 1; i < holeCount - 1; i++) { Point2D point = CalculatePointOnArc(slot.CenterPoint, arcRadius, currentAngle); positions.Add(point); if (slot.CounterClockwise) { currentAngle -= angleStep; } else { currentAngle += angleStep; } } } // 添加终点 if (holeCount > 1) { positions.Add(slot.EndPoint); } return positions; } /// /// 从钻带G85命令解析线段槽孔 /// /// G85命令字符串,格式:XxxxYxxxG85XxxxYxxx /// 槽孔宽度 /// 解析出的线段槽孔 public static LineSlot ParseLineSlotFromG85(string g85Command, double width) { var pattern = @"X([+-]?\d+\.?\d*)Y([+-]?\d+\.?\d*)G85X([+-]?\d+\.?\d*)Y([+-]?\d+\.?\d*)"; var match = Regex.Match(g85Command, pattern); if (match.Success) { // 提取原始坐标字符串 string startX = match.Groups[1].Value; string startY = match.Groups[2].Value; string endX = match.Groups[3].Value; string endY = match.Groups[4].Value; Point2D startPoint = new Point2D( double.Parse(startX) / 1000.0, double.Parse(startY) / 1000.0, $"X{startX}Y{startY}" ); Point2D endPoint = new Point2D( double.Parse(endX) / 1000.0, double.Parse(endY) / 1000.0, $"X{endX}Y{endY}" ); return new LineSlot(startPoint, endPoint, width); } throw new ArgumentException($"无效的G85命令格式: {g85Command}"); } // 辅助方法 /// /// 计算两点间欧氏距离 /// private static double CalculateDistance(Point2D p1, Point2D p2) { return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2)); } /// /// 计算方位角(度数) /// private static double CalculateAngle(Point2D startPoint, Point2D endPoint) { double angleRad = Math.Atan2(endPoint.Y - startPoint.Y, endPoint.X - startPoint.X); double angleDeg = angleRad * 180.0 / Math.PI; // 转换为0-360度范围 if (angleDeg < 0) angleDeg += 360; return angleDeg; } /// /// 计算弧段长度 /// public static double CalculateArcLength(ArcSlot arc) { double radius = arc.Radius; double angleDeg = CalculateArcAngle(arc); double angleRad = angleDeg * Math.PI / 180.0; return radius * angleRad; } /// /// 计算弧段圆心角(度数) /// private static double CalculateArcAngle(ArcSlot arc) { double startAngle = CalculateAngle(arc.CenterPoint, arc.StartPoint); double endAngle = CalculateAngle(arc.CenterPoint, arc.EndPoint); double angleSum; if (arc.CounterClockwise) { if (endAngle >= startAngle) angleSum = 360 - Math.Abs(startAngle - endAngle); else angleSum = Math.Abs(startAngle - endAngle); } else { if (startAngle >= endAngle) angleSum = 360 - Math.Abs(startAngle - endAngle); else angleSum = Math.Abs(startAngle - endAngle); } return angleSum; } /// /// 计算孔中心距 /// private static double CalculateHoleCenterDistance(double radius, double tolerance) { return Math.Sqrt(Math.Pow(radius, 2) - Math.Pow(radius - tolerance, 2)) * 2; } /// /// 根据起点、距离和角度计算下一个点 /// private static Point2D CalculateNextPoint(Point2D startPoint, double distance, double angleDeg) { double angleRad = angleDeg * Math.PI / 180.0; return new Point2D( startPoint.X + distance * Math.Cos(angleRad), startPoint.Y + distance * Math.Sin(angleRad) ); } /// /// 根据圆心、半径和角度计算圆弧上的点 /// private static Point2D CalculatePointOnArc(Point2D centerPoint, double radius, double angleDeg) { double angleRad = angleDeg * Math.PI / 180.0; return new Point2D( centerPoint.X + radius * Math.Cos(angleRad), centerPoint.Y + radius * Math.Sin(angleRad) ); } } }