feat: add single-point+normal overload to AssemblyEndFaceAnalyzer
- New Analyze(triangles, hitPoint, normal) bypasses 3-point seed plane construction - New Analyze(modelItem, hitPoint, normal) for Navisworks types - Same triangle extraction and centroid computation as 3-point version - Enables single-click end face detection via FaceInferToolPlugin
This commit is contained in:
parent
1e45546aed
commit
e7b5206198
@ -128,6 +128,108 @@ namespace NavisworksTransport.Utils.GeometryAnalysis
|
||||
$"端面识别完成: 三角形={candidateTriangles.Count}, 顶点={candidatePoints.Count}, 偏差={maxPlaneDeviation:F6}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单点+法向量分析端面。用于取面工具得到法向量后替代手工三点拾取。
|
||||
/// </summary>
|
||||
/// <param name="triangles">模型三角面片</param>
|
||||
/// <param name="hitPoint">命中点</param>
|
||||
/// <param name="normal">面法向量(需归一化)</param>
|
||||
public static EndFaceAnalysisResult Analyze(
|
||||
IEnumerable<AnalysisTriangle3> 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<AnalysisTriangle3>();
|
||||
var candidatePoints = new HashSet<Vector3>(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}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单点+法向量分析端面的 Navisworks 兼容重载。
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user