Files
wg_cpso/CaeCuttingForce/FlatendCutter/ClassicalCuttingForceCalculate.cs

291 lines
11 KiB
C#
Raw Normal View History

2026-03-25 18:20:24 +08:00
using CaeKnowledge.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using ToolPathParser;
namespace CaeCuttingForce.FlatendCutter
{
/// <summary>
/// 分情况进行经典切削力计算
/// </summary>
public static class ClassicalCuttingForceCalculate
{
/// <summary>
/// 按照轴向切深分组进行切削力计算
/// </summary>
public static void AxialDepthGroupedForceCalculator(List<ToolPosition> toolPosList, CuttingForceCoefficients coefficients, ToolParameters toolParams)
{
// 到位方向
int direction = SimpleMillingDirectionAnalyzer.AnalyzeDirection(toolPosList);
List<List<ToolPosition>> allLayers = LayerSplitter.SplitIntoLayersByZ(toolPosList);
List<List<ToolPosition>> firstDepthLayers = LayerSplitter.ExtractFirstAxialDepthLayers(allLayers);
var LineCalculator = new LineForce();
var ConcaveCurvesCalculator = new ConcaveCurvesForce();
var ConvexCurvesCalculator = new ConvexCurvesForce();
// 遍历每个提取到的层
// ReSharper disable once ForCanBeConvertedToForeach
for (int i = 0; i < firstDepthLayers.Count; i++)
{
// 每个 firstDepthLayers[i] 就是对应层的 List<ToolPosition>
List<ToolPosition> 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 == EnumSegmentType.Line) // By Luke修改
{
LineCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams);
}
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 == EnumSegmentType.Line) // By Luke修改
{
LineCalculator.CalculateCuttingForce(direction, point, coefficients, toolParams);
}
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($"警告: 点数不足,无法判断方向");
throw new Exception($"警告: 点数不足,无法判断方向");
}
}
new CuttingForceMapper().MapFirstLayerForceToSameDepth(allLayers, firstDepthLayers);
}
}
}
/// <summary>
/// 利用刀位点判断铣削方向
/// </summary>
public class SimpleMillingDirectionAnalyzer
{
public const int Clockwise = 2; // 顺时针
public const int CounterClockwise = 1; // 逆时针
public const int Undetermined = 0; // 无法确定
public static int AnalyzeDirection(List<ToolPosition> allPoints)
{
if (allPoints == null || allPoints.Count < 3)
return Undetermined;
double targetZ = allPoints[0].Z;
List<ToolPosition> layerPoints = new List<ToolPosition>();
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<ToolPosition> 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;
}
}
/// <summary>
/// 按刀位点原始顺序分层,提取所需要层
/// </summary>
public static class LayerSplitter
{
private const double Z_TOLERANCE = 0.001;
/// <summary>
/// 按刀位点原始顺序分层先遇到的Z值先成为层
/// </summary>
public static List<List<ToolPosition>> SplitIntoLayersByZ(List<ToolPosition> allPoints)
{
var allLayers = new List<List<ToolPosition>>();
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<ToolPosition> { point });
}
}
return allLayers;
}
/// <summary>
/// 从已分层的 allLayers 中,提取每个轴向切深首次出现的层
/// </summary>
/// <param name="allLayers">已按原始顺序分层的刀位点(外层=层,内层=该层点)</param>
/// <returns>每个轴向切深首次出现的层集合List<List<ToolPosition>></returns>
public static List<List<ToolPosition>> ExtractFirstAxialDepthLayers(List<List<ToolPosition>> allLayers)
{
// 存储已出现过的轴向切深(用于去重,判断是否首次出现)
HashSet<double> existedAxialDepths = new HashSet<double>();
List<List<ToolPosition>> firstDepthLayers = new List<List<ToolPosition>>();
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;
/// <summary>
/// 首层切削力映射到同切深其他层(按点索引复制)
/// </summary>
/// <param name="allLayers">所有分层(含首层+其他层)</param>
/// <param name="firstDepthLayers">已计算切削力的首层集合</param>
public void MapFirstLayerForceToSameDepth(List<List<ToolPosition>> allLayers, List<List<ToolPosition>> 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;
}
}
}
/// <summary>
/// 自定义浮点数比较器
/// </summary>
private class DoubleEqualityComparer : IEqualityComparer<double>
{
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();
}
}
}