using CaeGlobals; using CaeKnowledge; using CaeKnowledge.Data; using CaeKnowledge.View; using CaeMesh; using CaeModel; using Plankton; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace CPSO.Forms._92_Knowledge { public partial class FrmStepsManager : UserControls.FrmProperties { private readonly Controller Self; public FrmStepsManager(Controller self) { InitializeComponent(); Self = self; Text = @"分析模型定义"; gbProperties.Text = @"定义"; } public void PrepareForm() { if (propertyGrid.SelectedObject is ViewJobs jobs) { } } private void FrmAddLoad_Load(object sender, EventArgs e) { var jobs = new ViewJobs(Self); // 初始化下拉菜单 jobs.PopulateDropDownList(); // 初始化刀位文件列表 jobs.ToolPositionList.Clear(); if (Self?.ToolPositions != null) { jobs.ToolPositionList.AddRange(Self.ToolPositions); } propertyGrid.SelectedObject = jobs; } protected override async void OnApply(bool onOkAddNew) { try { if (!(propertyGrid.SelectedObject is ViewJobs viewSteps)) return; // 基础计算步 Step baseStep = Self.GetStep(viewSteps.Step); // Todo: 检查基础计算步 if (baseStep == null) throw new CaeException($"无法找到对应的计算步:{viewSteps.Step}"); if (!Self.Model.Mesh.Surfaces.TryGetValue(viewSteps.Surface, out var surface)) throw new CaeException($"无法找到对应的曲面集:{viewSteps.Surface}"); Self.Form.SetStateWorking(@"构建切削力分析模型..."); // 1. 先把所有计算步反激活 var stepList = Self.GetAllSteps().ToList(); stepList.ForEach(x => { Self.ActivateDeactivateStep(x.Name, false); }); // 2. 加载网格 var mesh = LoadMesh(surface); List jobs = new List(); await Task.Run(() => { foreach (var tp in Self.ToolPositions) { // 1. 计算最接近的顶点 int vertId = GetClosedVertex(mesh, tp.Base); // PlanktonMesh中存储的Id if (vertId < 0) // 找不到最近节点,继续执行 { continue; } // 2. 最接近节点 // int nodeId = _vertexToNodeMapping[vertId]; // 全局网格中的Id FeNode node = Self.Model.Mesh.Nodes[_vertexToNodeMapping[vertId]]; // 3. 最近节点周围的面单元 List faces = new List(); foreach (var f in mesh.Vertices.GetVertexFaces(vertId)) { if (_cellToFaceMapping.TryGetValue(f, out var face)) { faces.Add(face); } } // 4. 复制一份基础计算步并激活 var newStep = Self.GetStep(baseStep.Name).DeepClone(); var stepName = viewSteps.NewStepName; newStep.Name = Self.GetStepNames().GetNextNumberedKey(NamedClass.GetNameWithoutLastValue(stepName)); Self.AddStep(newStep, false, false); // 激活计算步 Self.ActivateDeactivateStep(newStep.Name, true); // 5. 添加载荷 // 5.1 新建用于施加载荷的曲面Surface // 新建User Surface var userSurface = new FeSurface(Self.Model.Mesh.Surfaces.GetNextNumberedKey("UserSurface")) { CreatedFrom = FeSurfaceCreatedFrom.Selection, FaceIds = faces.Select(x => x.Id).ToArray(), // ToDo: 未来修改 Internal = false, }; Self.AddSurface(userSurface); // 5.2 定义载荷 bool twoD = Self.Model.Properties.ModelSpace.IsTwoD(); bool complex = newStep is SteadyStateDynamicsStep; var loadName = newStep.Loads.GetNextNumberedKey("Load"); double area = userSurface.Area; if (area <= 0) area = 1.0; double fx = -1.0 * tp.MaxFx / area; double fy = -1.0 * tp.MaxFx / area; double fz = -1.0 * tp.MaxFz / area; var stLoad = new STLoad(loadName, userSurface.Name, RegionTypeEnum.SurfaceName, fx, fy, fz, twoD, complex, 0); // 5.3 添加载荷 Self.AddLoad(newStep.Name, stLoad); // 6. 添加到 List jobs jobs.Add(new ProcessingJob(tp.Base) { StepName = newStep.Name, SurfaceName = userSurface.Name, }); } }); Self.ProcessingJobs.Clear(); jobs.ForEach(x => { Self.ProcessingJobs.Add(new ViewProcessingJob(x)); }); Self.Form.SetStateReady(@"构建切削力分析模型..."); } catch (Exception ex) { ExceptionTools.Show(ex); Self.Form.SetStateReady(@"构建切削力分析模型..."); } } // 计算最接近的点 private static int GetClosedVertex(PlanktonMesh mesh, ToolPosition toolPosition) { int closedVertexIndex = -1; double x1 = toolPosition.X; double y1 = toolPosition.Y; double z1 = toolPosition.Z; double minimumDistance = double.MaxValue; int id = 0; foreach (var vertex in mesh.Vertices) { double x2 = vertex.X; double y2 = vertex.Y; double z2 = vertex.Z; double dst = MeshTools.Distance(x1, y1, z1, x2, y2, z2); // 如果距离小于当前最小距离,则更新最近点索引 if (dst < minimumDistance) { minimumDistance = dst; closedVertexIndex = id; } id++; } return closedVertexIndex; } private readonly Dictionary _nodeToVertexMapping = new Dictionary(); private readonly Dictionary _vertexToNodeMapping = new Dictionary(); private readonly Dictionary _cellToFaceMapping = new Dictionary(); private PlanktonMesh LoadMesh(FeSurface surface) { // 计算面列表 var faceList = (from faceId in surface.FaceIds let element = Self.Model.Mesh.Elements[faceId / 10] let faceName = (FeFaceName)(faceId % 10 + 1) select new FeFace(element, faceName)).ToList(); // 节点列表 var hashSet = new HashSet(); faceList.ForEach(face => { var ids = face.NodeIds; hashSet.Add(ids[0]); hashSet.Add(ids[1]); hashSet.Add(ids[2]); }); var mesh = new PlanktonMesh(); foreach (var nodeId in hashSet.OrderBy(x => x)) { double x = Self.Model.Mesh.Nodes[nodeId].X; double y = Self.Model.Mesh.Nodes[nodeId].Y; double z = Self.Model.Mesh.Nodes[nodeId].Z; int vertId = mesh.Vertices.Add(x, y, z); _nodeToVertexMapping.Add(nodeId, vertId); _vertexToNodeMapping.Add(vertId, nodeId); } faceList.ForEach(face => { var ids = face.NodeIds; int i = _nodeToVertexMapping[ids[0]]; int j = _nodeToVertexMapping[ids[1]]; int k = _nodeToVertexMapping[ids[2]]; int cellId = mesh.Faces.AddFace(i, j, k); _cellToFaceMapping.Add(cellId, face); }); return mesh; } } }