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);