using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using ToolPathParser; namespace ClassicalCuttingForce { /// /// 分情况进行经典切削力计算 /// public class ClassicalCuttingForceCalculate { /// /// 按照轴向切深分组进行切削力计算 /// public void AxialDepthGroupedForceCalculator(List toolPosList, CuttingForceCoefficients coefficients, ToolParameters toolParams) { int direction = SimpleMillingDirectionAnalyzer.AnalyzeDirection(toolPosList); List> allLayers = LayerSplitter.SplitIntoLayersByZ(toolPosList); List> firstDepthLayers = LayerSplitter.ExtractFirstAxialDepthLayers(allLayers); var LineCalculator = new LineForce(); var ConcaveCurvesCalculator = new ConcaveCurvesForce(); var ConvexCurvesCalculator = new ConvexCurvesForce(); // 遍历每个提取到的层 for (int i = 0; i < firstDepthLayers.Count; i++) { // 每个 firstDepthLayers[i] 就是对应层的 List List targetLayer = firstDepthLayers[i]; double targetDepth = targetLayer[0].AxialDepth; int layerIndexInAllLayers = allLayers.IndexOf(targetLayer) + 1; foreach (var point in targetLayer) { if (direction == 1)//逆时针 { if (point.SegmentType == 1) { LineCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams); } else if (point.SegmentType == 2) { if (point.K == -1) { ConcaveCurvesCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams); } else if (point.K == 1) { ConvexCurvesCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams); } } } else if (direction == 2)//顺时针 { if (point.SegmentType == 1) { LineCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams); } else if (point.SegmentType == 2) { if (point.K == 1) { ConcaveCurvesCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams); } else if (point.K == -1) { ConvexCurvesCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams); } } } else { Console.WriteLine($"警告: 点数不足,无法判断方向"); } } new CuttingForceMapper().MapFirstLayerForceToSameDepth(allLayers, firstDepthLayers); } } } /// /// 利用刀位点判断铣削方向 /// public class SimpleMillingDirectionAnalyzer { public const int Clockwise = 2; // 顺时针 public const int CounterClockwise = 1; // 逆时针 public const int Undetermined = 0; // 无法确定 public static int AnalyzeDirection(List allPoints) { if (allPoints == null || allPoints.Count < 3) return Undetermined; double targetZ = allPoints[0].Z; List layerPoints = new List(); foreach (ToolPosition point in allPoints) { if (point.Z == targetZ) { layerPoints.Add(point); } } if (layerPoints.Count < 3) { //Console.WriteLine($"警告: Z={targetZ}层的点数不足({layerPoints.Count}),无法判断方向"); return Undetermined; } double area = CalculateSignedArea(layerPoints); if (Math.Abs(area) < 1e-10) return Undetermined; return area > 0 ? CounterClockwise : Clockwise; } // 计算有向面积 private static double CalculateSignedArea(List points) { double area = 0; int n = points.Count; for (int i = 0; i < n; i++) { ToolPosition current = points[i]; ToolPosition next = points[(i + 1) % n]; area += (current.X * next.Y - next.X * current.Y); } return area / 2.0; } } /// /// 按刀位点原始顺序分层,提取所需要层 /// public static class LayerSplitter { private const double Z_TOLERANCE = 0.001; /// /// 按刀位点原始顺序分层(先遇到的Z值先成为层) /// public static List> SplitIntoLayersByZ(List allPoints) { List> allLayers = new List>(); if (allPoints == null || allPoints.Count == 0) return allLayers; foreach (var point in allPoints) { var existingLayer = allLayers.FirstOrDefault(layer => Math.Abs(layer[0].Z - point.Z) <= Z_TOLERANCE); if (existingLayer != null) { existingLayer.Add(point); } else { allLayers.Add(new List { point }); } } return allLayers; } /// /// 从已分层的 allLayers 中,提取每个轴向切深首次出现的层 /// /// 已按原始顺序分层的刀位点(外层=层,内层=该层点) /// 每个轴向切深首次出现的层集合(List>) public static List> ExtractFirstAxialDepthLayers(List> allLayers) { // 存储已出现过的轴向切深(用于去重,判断是否首次出现) HashSet existedAxialDepths = new HashSet(); List> firstDepthLayers = new List>(); const double AXIAL_DEPTH_TOLERANCE = 0.001; // 空值判断,避免报错 if (allLayers == null || allLayers.Count == 0) return firstDepthLayers; // 按原始顺序遍历 allLayers 中的每一层 foreach (var currentLayer in allLayers) { if (currentLayer == null || currentLayer.Count == 0) continue; double currentAxialDepth = currentLayer[0].AxialDepth; bool isFirstAppearance = !existedAxialDepths .Any(depth => Math.Abs(depth - currentAxialDepth) <= AXIAL_DEPTH_TOLERANCE); if (isFirstAppearance) { existedAxialDepths.Add(currentAxialDepth); firstDepthLayers.Add(currentLayer); } } return firstDepthLayers; } } public class CuttingForceMapper { private const double TOLERANCE = 0.001; /// /// 首层切削力映射到同切深其他层(按点索引复制) /// /// 所有分层(含首层+其他层) /// 已计算切削力的首层集合 public void MapFirstLayerForceToSameDepth(List> allLayers, List> firstDepthLayers) { // 构建「切深→首层」映射 var depthFirstLayerMap = firstDepthLayers .Where(layer => layer != null && layer.Count > 0) .ToDictionary( layer => layer[0].AxialDepth, layer => layer, new DoubleEqualityComparer(TOLERANCE) ); // 遍历所有层,复制切削力 foreach (var currentLayer in allLayers) { if (currentLayer == null || currentLayer.Count == 0) continue; double currentDepth = currentLayer[0].AxialDepth; if (!depthFirstLayerMap.TryGetValue(currentDepth, out var firstLayer) || firstDepthLayers.Contains(currentLayer)) continue; if (firstLayer.Count != currentLayer.Count) continue; for (int i = 0; i < firstLayer.Count; i++) { var firstPoint = firstLayer[i]; var currentPoint = currentLayer[i]; currentPoint.AverageFx = firstPoint.AverageFx; currentPoint.AverageFy = firstPoint.AverageFy; currentPoint.AverageFz = firstPoint.AverageFz; currentPoint.MaxFx = firstPoint.MaxFx; currentPoint.MaxFy = firstPoint.MaxFy; currentPoint.MaxFz = firstPoint.MaxFz; } } } /// /// 自定义浮点数比较器 /// private class DoubleEqualityComparer : IEqualityComparer { private readonly double _tolerance; public DoubleEqualityComparer(double tolerance) => _tolerance = tolerance; public bool Equals(double x, double y) => Math.Abs(x - y) <= _tolerance; public int GetHashCode(double obj) => obj.ToString("F3").GetHashCode(); } } }