using CaeKnowledge.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using ToolPathParser;
namespace CaeCuttingForce.ToroidalCutter
{
///
/// 分情况进行经典切削力计算
///
public static class ClassicalCuttingForceCalculate
{
///
/// 按照轴向切深分组进行切削力计算
///
public static 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)
if (point.SegmentType == EnumSegmentType.Line) // By Luke修改
{
LineCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams);
}
// else if (point.SegmentType == 2)
else if (point.SegmentType == EnumSegmentType.Arc) // By Luke修改
{
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)
if (point.SegmentType == EnumSegmentType.Line) // By Luke修改
{
LineCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams);
}
// else if (point.SegmentType == 2)
else if (point.SegmentType == EnumSegmentType.Arc) // By Luke修改
{
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();
}
}
}