Files
wg_cpso/CuttingForce2/ClassicalCuttingForceCalculate.cs
2026-03-25 18:20:24 +08:00

308 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using ToolPathParser;
namespace ClassicalCuttingForce
{
/// <summary>
/// 分情况进行经典切削力计算
/// </summary>
public class ClassicalCuttingForceCalculate
{
/// <summary>
/// 按照轴向切深分组进行切削力计算
/// </summary>
public 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();
// 遍历每个提取到的层
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 == 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);
}
}
}
/// <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)
{
List<List<ToolPosition>> 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();
}
}
}