diff --git a/src/Utils/Assembly/AssemblyEndFaceAnalyzer.cs b/src/Utils/Assembly/AssemblyEndFaceAnalyzer.cs index d77cb63..adf5934 100644 --- a/src/Utils/Assembly/AssemblyEndFaceAnalyzer.cs +++ b/src/Utils/Assembly/AssemblyEndFaceAnalyzer.cs @@ -128,6 +128,108 @@ namespace NavisworksTransport.Utils.GeometryAnalysis $"端面识别完成: 三角形={candidateTriangles.Count}, 顶点={candidatePoints.Count}, 偏差={maxPlaneDeviation:F6}"); } + /// + /// 单点+法向量分析端面。用于取面工具得到法向量后替代手工三点拾取。 + /// + /// 模型三角面片 + /// 命中点 + /// 面法向量(需归一化) + public static EndFaceAnalysisResult Analyze( + IEnumerable triangles, + Vector3 hitPoint, + Vector3 normal) + { + if (triangles == null) + throw new ArgumentNullException(nameof(triangles)); + + if (normal.LengthSquared() < 1e-12f) + return EndFaceAnalysisResult.Failure("法向量长度过小。"); + + var triangleList = triangles.ToList(); + if (triangleList.Count == 0) + return EndFaceAnalysisResult.Failure("没有可用的三角几何数据。"); + + var seedPlane = new PlaneDefinition(Vector3.Normalize(normal), Vector3.Dot(normal, hitPoint)); + + var candidateTriangles = new List(); + var candidatePoints = new HashSet(new Vector3EqualityComparer()); + double maxPlaneDeviation = 0.0; + + foreach (var triangle in triangleList) + { + if (!TryGetTriangleNormal(triangle, out Vector3 triangleNormal)) + continue; + + if (Math.Abs(Vector3.Dot(triangleNormal, seedPlane.Normal)) < NormalAlignmentCosineThreshold) + continue; + + double d1 = Math.Abs(GetSignedDistanceToPlane(seedPlane, triangle.Point1)); + double d2 = Math.Abs(GetSignedDistanceToPlane(seedPlane, triangle.Point2)); + double d3 = Math.Abs(GetSignedDistanceToPlane(seedPlane, triangle.Point3)); + double triangleDeviation = Math.Max(d1, Math.Max(d2, d3)); + if (triangleDeviation > PlaneDistanceTolerance) + continue; + + candidateTriangles.Add(triangle); + candidatePoints.Add(ProjectPointToPlane(seedPlane, triangle.Point1)); + candidatePoints.Add(ProjectPointToPlane(seedPlane, triangle.Point2)); + candidatePoints.Add(ProjectPointToPlane(seedPlane, triangle.Point3)); + maxPlaneDeviation = Math.Max(maxPlaneDeviation, triangleDeviation); + } + + if (candidateTriangles.Count == 0 || candidatePoints.Count < 3) + return EndFaceAnalysisResult.Failure("没有识别到足够的端面共面三角形。"); + + PlaneDefinition refinedPlane = RefinePlane(seedPlane, candidatePoints); + PlaneBasis planeBasis = CreatePlaneBasis(refinedPlane); + + double minU = double.MaxValue; + double maxU = double.MinValue; + double minV = double.MaxValue; + double maxV = double.MinValue; + + foreach (Vector3 candidatePoint in candidatePoints) + { + Vector2 projected = ProjectToPlane2D(candidatePoint, planeBasis); + minU = Math.Min(minU, projected.X); + maxU = Math.Max(maxU, projected.X); + minV = Math.Min(minV, projected.Y); + maxV = Math.Max(maxV, projected.Y); + } + + double extentU = maxU - minU; + double extentV = maxV - minV; + if (extentU < MinimumProjectedExtent || extentV < MinimumProjectedExtent) + { + return EndFaceAnalysisResult.Failure("识别到的端面分布过窄,无法稳定求中心。"); + } + + Vector3 center = ProjectFromPlane2D((minU + maxU) / 2.0, (minV + maxV) / 2.0, planeBasis); + + return EndFaceAnalysisResult.Success( + center, + refinedPlane.Normal, + candidateTriangles.Count, + candidatePoints.Count, + maxPlaneDeviation, + $"端面识别完成(单点法向): 三角形={candidateTriangles.Count}, 顶点={candidatePoints.Count}, 偏差={maxPlaneDeviation:F6}"); + } + + /// + /// 单点+法向量分析端面的 Navisworks 兼容重载。 + /// + public static EndFaceAnalysisResult Analyze(ModelItem modelItem, Point3D hitPoint, Vector3D normal) + { + if (modelItem == null) + throw new ArgumentNullException(nameof(modelItem)); + + var triangles = GeometryHelper.ExtractTriangles(new[] { modelItem }) + .Select(ConvertTriangle) + .ToList(); + + return Analyze(triangles, ToVector3(hitPoint), new Vector3((float)normal.X, (float)normal.Y, (float)normal.Z)); + } + public static Point3D ToPoint3D(Vector3 point) { return new Point3D(point.X, point.Y, point.Z);