406 lines
14 KiB
C#
406 lines
14 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text.RegularExpressions;
|
||
|
||
namespace DrillTools
|
||
{
|
||
/// <summary>
|
||
/// 二维点结构
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从钻带坐标字符串创建点(格式:X+/-数字Y+/-数字)
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 线段槽孔结构
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取槽孔长度
|
||
/// </summary>
|
||
public double Length => Math.Sqrt(Math.Pow(StartPoint.X - EndPoint.X, 2) + Math.Pow(StartPoint.Y - EndPoint.Y, 2));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 弧段槽孔结构
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取弧段半径
|
||
/// </summary>
|
||
public double Radius => Math.Sqrt(Math.Pow(StartPoint.X - CenterPoint.X, 2) + Math.Pow(StartPoint.Y - CenterPoint.Y, 2));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 槽孔钻孔数量计算工具类
|
||
/// 提供与CAM350一致的槽孔孔数计算方法
|
||
/// </summary>
|
||
public static class SlotHoleCalculator
|
||
{
|
||
/// <summary>
|
||
/// 默认凸位高度值(CAM350标准,单位:mm)
|
||
/// </summary>
|
||
private const double DEFAULT_TOLERANCE = 0.0127;
|
||
|
||
/// <summary>
|
||
/// 计算线段槽孔的钻孔数量
|
||
/// </summary>
|
||
/// <param name="slot">线段槽孔参数</param>
|
||
/// <param name="tolerance">凸位高度值,默认为0.0127mm(CAM350标准)</param>
|
||
/// <returns>需要的钻孔数量</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算弧段槽孔的钻孔数量
|
||
/// </summary>
|
||
/// <param name="slot">弧段槽孔参数</param>
|
||
/// <param name="tolerance">凸位高度值,默认为0.0127mm(CAM350标准)</param>
|
||
/// <returns>需要的钻孔数量</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算线段槽孔的钻孔位置
|
||
/// </summary>
|
||
/// <param name="slot">线段槽孔参数</param>
|
||
/// <param name="tolerance">凸位高度值,默认为0.0127mm(CAM350标准)</param>
|
||
/// <returns>钻孔位置列表</returns>
|
||
public static List<Point2D> CalculateLineSlotHolePositions(LineSlot slot, double tolerance = DEFAULT_TOLERANCE)
|
||
{
|
||
List<Point2D> positions = new List<Point2D>();
|
||
|
||
// 计算孔半径
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算弧段槽孔的钻孔位置
|
||
/// </summary>
|
||
/// <param name="slot">弧段槽孔参数</param>
|
||
/// <param name="tolerance">凸位高度值,默认为0.0127mm(CAM350标准)</param>
|
||
/// <returns>钻孔位置列表</returns>
|
||
public static List<Point2D> CalculateArcSlotHolePositions(ArcSlot slot, double tolerance = DEFAULT_TOLERANCE)
|
||
{
|
||
List<Point2D> positions = new List<Point2D>();
|
||
|
||
// 计算孔半径
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从钻带G85命令解析线段槽孔
|
||
/// </summary>
|
||
/// <param name="g85Command">G85命令字符串,格式:XxxxYxxxG85XxxxYxxx</param>
|
||
/// <param name="width">槽孔宽度</param>
|
||
/// <returns>解析出的线段槽孔</returns>
|
||
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}");
|
||
}
|
||
|
||
// 辅助方法
|
||
|
||
/// <summary>
|
||
/// 计算两点间欧氏距离
|
||
/// </summary>
|
||
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));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算方位角(度数)
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算弧段长度
|
||
/// </summary>
|
||
public static double CalculateArcLength(ArcSlot arc)
|
||
{
|
||
double radius = arc.Radius;
|
||
double angleDeg = CalculateArcAngle(arc);
|
||
double angleRad = angleDeg * Math.PI / 180.0;
|
||
return radius * angleRad;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算弧段圆心角(度数)
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算孔中心距
|
||
/// </summary>
|
||
private static double CalculateHoleCenterDistance(double radius, double tolerance)
|
||
{
|
||
return Math.Sqrt(Math.Pow(radius, 2) - Math.Pow(radius - tolerance, 2)) * 2;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据起点、距离和角度计算下一个点
|
||
/// </summary>
|
||
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)
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据圆心、半径和角度计算圆弧上的点
|
||
/// </summary>
|
||
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)
|
||
);
|
||
}
|
||
}
|
||
} |