using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Autodesk.Navisworks.Api;
using ComApi = Autodesk.Navisworks.Api.Interop.ComApi;
using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
namespace NavisworksTransport
{
///
/// 几何提取器 - 使用改进的算法和性能优化
///
public class GeometryExtractor
{
///
/// 提取模型项的顶视图轮廓
///
/// 模型项
/// 容差
/// 轮廓点集合
public static List ExtractTopViewOutline(ModelItem modelItem, double tolerance = 0.5)
{
var points = new List();
try
{
LogManager.WriteLog($"开始提取模型 {modelItem.DisplayName} 的几何数据");
LogManager.WriteLog($"模型项类型: {modelItem.GetType().Name}");
LogManager.WriteLog($"模型项GUID: {modelItem.InstanceGuid}");
// 详细检查模型是否有几何数据
bool hasGeometry = modelItem.HasGeometry;
LogManager.WriteLog($"[关键检查] ModelItem.HasGeometry = {hasGeometry}");
if (!hasGeometry)
{
LogManager.WriteLog("[关键发现] 模型项没有几何数据 - HasGeometry 返回 false");
LogManager.WriteLog($"模型项详细信息:");
LogManager.WriteLog($" - 显示名称: {modelItem.DisplayName}");
LogManager.WriteLog($" - 实例GUID: {modelItem.InstanceGuid}");
// 检查子项数量来判断是否为叶节点
int childrenCount = modelItem.Children.Count();
LogManager.WriteLog($" - 子项数量: {childrenCount}");
LogManager.WriteLog($" - 是否为叶节点: {childrenCount == 0}");
// 尝试检查包围盒
try
{
var bbox = modelItem.BoundingBox();
if (bbox != null)
{
LogManager.WriteLog($" - 包围盒存在: {bbox.Min} - {bbox.Max}");
}
else
{
LogManager.WriteLog($" - 包围盒不存在");
}
}
catch (Exception bboxEx)
{
LogManager.WriteLog($" - 获取包围盒失败: {bboxEx.Message}");
}
return points;
}
LogManager.WriteLog("[几何检查通过] 模型项有几何数据,继续处理");
// 处理多实例问题 - 确保只获取当前实例的几何
var targetItem = modelItem;
int instanceCount = targetItem.Instances.Count();
LogManager.WriteLog($"原始模型实例数: {instanceCount}");
while (targetItem.Instances.Count() > 1)
{
targetItem = targetItem.Parent;
if (targetItem == null) break;
LogManager.WriteLog($"向上查找父项: {targetItem?.DisplayName}, 实例数: {targetItem?.Instances.Count()}");
}
if (targetItem == null)
{
LogManager.WriteLog("无法找到合适的几何节点");
return points;
}
// 再次检查目标项的几何状态
bool targetHasGeometry = targetItem.HasGeometry;
LogManager.WriteLog($"[目标项检查] 使用几何节点: {targetItem.DisplayName}");
LogManager.WriteLog($"[目标项检查] 实例数: {targetItem.Instances.Count()}");
LogManager.WriteLog($"[目标项检查] HasGeometry = {targetHasGeometry}");
if (!targetHasGeometry)
{
LogManager.WriteLog("[目标项问题] 目标节点也没有几何数据");
return points;
}
// 使用优化的几何提取方法
var triangles = ExtractTrianglesOptimized(targetItem);
LogManager.WriteLog($"提取到 {triangles.Count} 个三角形");
if (triangles.Count > 0)
{
// 生成轮廓
points = GenerateOutlineFromTriangles(triangles, tolerance);
LogManager.WriteLog($"生成轮廓包含 {points.Count} 个点");
}
else
{
LogManager.WriteLog("未提取到三角形数据");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"提取几何数据失败: {ex.Message}");
LogManager.WriteLog($"堆栈跟踪: {ex.StackTrace}");
}
return points;
}
///
/// 优化的三角形提取方法
///
/// 模型项
/// 三角形集合
private static List ExtractTrianglesOptimized(ModelItem modelItem)
{
var triangles = new List();
try
{
// 转换为 COM 选择
var modelCollection = new ModelItemCollection();
modelCollection.Add(modelItem);
var comState = ComApiBridge.State;
var comSelection = ComApiBridge.ToInwOpSelection(modelCollection);
LogManager.WriteLog($"COM 选择创建成功,路径数: {comSelection.Paths().Count}");
// 使用优化的片段去重方法
var uniqueFragments = GetUniqueFragments(comSelection);
LogManager.WriteLog($"获取到 {uniqueFragments.Count} 个唯一片段");
foreach (var fragmentInfo in uniqueFragments)
{
try
{
var callback = new OptimizedGeometryCallback(fragmentInfo.Transform);
fragmentInfo.Fragment.GenerateSimplePrimitives(
ComApi.nwEVertexProperty.eNORMAL,
callback);
var fragmentTriangles = callback.GetTriangles();
triangles.AddRange(fragmentTriangles);
LogManager.WriteLog($"片段生成了 {fragmentTriangles.Count} 个三角形");
}
catch (Exception ex)
{
LogManager.WriteLog($"处理片段失败: {ex.Message}");
}
}
}
catch (Exception ex)
{
LogManager.WriteLog($"提取三角形失败: {ex.Message}");
}
return triangles;
}
///
/// 获取唯一的片段(解决多实例问题)
///
/// COM 选择
/// 唯一片段信息集合
private static List GetUniqueFragments(ComApi.InwOpSelection selection)
{
var fragmentMap = new Dictionary();
try
{
foreach (ComApi.InwOaPath3 path in selection.Paths())
{
try
{
foreach (ComApi.InwOaFragment3 fragment in path.Fragments())
{
try
{
// 获取片段的唯一标识
var pathArray = ((Array)fragment.path.ArrayData).ToArray();
var pathKey = string.Join(",", pathArray);
if (!fragmentMap.ContainsKey(pathKey))
{
// 获取变换矩阵
var transform = (ComApi.InwLTransform3f3)(object)fragment.GetLocalToWorldMatrix();
fragmentMap[pathKey] = new FragmentInfo
{
Fragment = fragment,
Transform = transform,
PathKey = pathKey
};
}
}
catch (Exception ex)
{
LogManager.WriteLog($"处理单个片段失败: {ex.Message}");
}
}
}
catch (Exception ex)
{
LogManager.WriteLog($"遍历路径片段失败: {ex.Message}");
}
}
}
catch (Exception ex)
{
LogManager.WriteLog($"获取唯一片段失败: {ex.Message}");
}
return fragmentMap.Values.ToList();
}
///
/// 从三角形生成轮廓
///
/// 三角形集合
/// 容差
/// 轮廓点集合
private static List GenerateOutlineFromTriangles(List triangles, double tolerance)
{
var outlinePoints = new List();
try
{
if (triangles.Count == 0) return outlinePoints;
// 找到最高的 Z 坐标
var maxZ = triangles.SelectMany(t => new[] { t.Point1.Z, t.Point2.Z, t.Point3.Z }).Max();
LogManager.WriteLog($"最高 Z 坐标: {maxZ}");
// 筛选顶部表面的三角形
var topTriangles = triangles.Where(t =>
Math.Abs(t.Point1.Z - maxZ) < tolerance &&
Math.Abs(t.Point2.Z - maxZ) < tolerance &&
Math.Abs(t.Point3.Z - maxZ) < tolerance).ToList();
LogManager.WriteLog($"顶部三角形数量: {topTriangles.Count}");
if (topTriangles.Count == 0) return outlinePoints;
// 提取所有边
var edges = new List();
foreach (var triangle in topTriangles)
{
edges.Add(new Edge2D(
new Point2D(triangle.Point1.X, triangle.Point1.Y),
new Point2D(triangle.Point2.X, triangle.Point2.Y)));
edges.Add(new Edge2D(
new Point2D(triangle.Point2.X, triangle.Point2.Y),
new Point2D(triangle.Point3.X, triangle.Point3.Y)));
edges.Add(new Edge2D(
new Point2D(triangle.Point3.X, triangle.Point3.Y),
new Point2D(triangle.Point1.X, triangle.Point1.Y)));
}
// 找到边界边(只出现一次的边)
var boundaryEdges = FindBoundaryEdges(edges);
LogManager.WriteLog($"边界边数量: {boundaryEdges.Count}");
if (boundaryEdges.Count > 0)
{
// 构建轮廓
var outlinePoints2D = BuildOutlineFromEdges(boundaryEdges);
// 转换为3D点(使用最高Z坐标)
outlinePoints = outlinePoints2D.Select(p => new Point3D(p.X, p.Y, maxZ)).ToList();
LogManager.WriteLog($"最终轮廓点数量: {outlinePoints.Count}");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"生成轮廓失败: {ex.Message}");
}
return outlinePoints;
}
///
/// 查找边界边(在俯视图中只出现一次的边)
///
/// 所有边的集合
/// 边界边集合
private static List FindBoundaryEdges(List edges)
{
var boundaryEdges = new List();
var edgeCount = new Dictionary();
var edgeMap = new Dictionary();
try
{
LogManager.WriteLog($"开始查找边界边,总边数: {edges.Count}");
// 统计每条边出现的次数
foreach (var edge in edges)
{
var key = edge.GetKey();
var reverseKey = edge.GetReverseKey();
// 使用规范化的边键(总是用较小的端点作为起点)
var normalizedKey = string.Compare(key, reverseKey) < 0 ? key : reverseKey;
var normalizedEdge = string.Compare(key, reverseKey) < 0 ? edge : new Edge2D(edge.End, edge.Start);
if (edgeCount.ContainsKey(normalizedKey))
{
edgeCount[normalizedKey]++;
}
else
{
edgeCount[normalizedKey] = 1;
edgeMap[normalizedKey] = normalizedEdge;
}
}
LogManager.WriteLog($"边计数完成,唯一边数: {edgeCount.Count}");
// 找出只出现一次的边(边界边)
int boundaryCount = 0;
int sharedCount = 0;
foreach (var kvp in edgeCount)
{
if (kvp.Value == 1)
{
boundaryEdges.Add(edgeMap[kvp.Key]);
boundaryCount++;
}
else
{
sharedCount++;
}
}
LogManager.WriteLog($"边界边分析完成:");
LogManager.WriteLog($" 边界边数量: {boundaryCount}");
LogManager.WriteLog($" 共享边数量: {sharedCount}");
LogManager.WriteLog($" 边界/总边比例: {(double)boundaryCount / edges.Count:P1}");
// 验证边界边的连通性
if (boundaryEdges.Count > 0)
{
var connectivity = AnalyzeBoundaryConnectivity(boundaryEdges);
LogManager.WriteLog($"边界边连通性分析: {connectivity}");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"查找边界边失败: {ex.Message}");
}
return boundaryEdges;
}
///
/// 分析边界边的连通性
///
/// 边界边集合
/// 连通性分析字符串
private static string AnalyzeBoundaryConnectivity(List boundaryEdges)
{
try
{
var vertexConnectionCount = new Dictionary();
// 统计每个顶点的连接数
foreach (var edge in boundaryEdges)
{
var startKey = $"{edge.Start.X:F3},{edge.Start.Y:F3}";
var endKey = $"{edge.End.X:F3},{edge.End.Y:F3}";
vertexConnectionCount[startKey] = (vertexConnectionCount.ContainsKey(startKey) ? vertexConnectionCount[startKey] : 0) + 1;
vertexConnectionCount[endKey] = (vertexConnectionCount.ContainsKey(endKey) ? vertexConnectionCount[endKey] : 0) + 1;
}
// 分析连接模式
int isolatedVertices = 0; // 度数为1的顶点
int normalVertices = 0; // 度数为2的顶点
int junctionVertices = 0; // 度数>2的顶点
foreach (var count in vertexConnectionCount.Values)
{
if (count == 1) isolatedVertices++;
else if (count == 2) normalVertices++;
else junctionVertices++;
}
return $"顶点: {vertexConnectionCount.Count}, 孤立: {isolatedVertices}, 正常: {normalVertices}, 连接点: {junctionVertices}";
}
catch (Exception ex)
{
return $"连通性分析失败: {ex.Message}";
}
}
///
/// 从边界边构建轮廓点集合(支持多轮廓)
///
/// 边界边集合
/// 轮廓点集合
private static List BuildOutlineFromEdges(List edges)
{
var allOutlinePoints = new List();
var remainingEdges = new List(edges);
var contourCount = 0;
try
{
LogManager.WriteLog($"开始构建轮廓,总边数: {edges.Count}");
while (remainingEdges.Count > 0 && contourCount < 10) // 最多处理10个轮廓
{
contourCount++;
LogManager.WriteLog($"=== 开始构建第 {contourCount} 个轮廓 ===");
var currentContour = BuildSingleContour(remainingEdges);
if (currentContour.Count >= 3) // 至少3个点才能形成有效轮廓
{
LogManager.WriteLog($"第 {contourCount} 个轮廓包含 {currentContour.Count} 个点");
allOutlinePoints.AddRange(currentContour);
// 添加轮廓分隔符(使用特殊坐标标记)
if (contourCount > 1)
{
allOutlinePoints.Add(new Point2D(double.NaN, double.NaN)); // 轮廓分隔符
}
}
else
{
LogManager.WriteLog($"第 {contourCount} 个轮廓点数不足({currentContour.Count}),跳过");
break; // 如果轮廓太小,可能是噪声,停止处理
}
}
LogManager.WriteLog($"轮廓构建完成,共 {contourCount} 个轮廓,总点数: {allOutlinePoints.Count}");
// 如果有多个轮廓,返回最大的外部轮廓
if (contourCount > 1)
{
LogManager.WriteLog("检测到多个轮廓,返回最大轮廓作为外部边界");
return GetLargestContour(allOutlinePoints);
}
}
catch (Exception ex)
{
LogManager.WriteLog($"构建轮廓失败: {ex.Message}");
}
return allOutlinePoints;
}
///
/// 构建单个连续轮廓
///
/// 剩余边集合(会被修改)
/// 单个轮廓的点集合
private static List BuildSingleContour(List remainingEdges)
{
var contour = new List();
try
{
if (remainingEdges.Count == 0) return contour;
// 从第一条边开始
var currentEdge = remainingEdges[0];
remainingEdges.RemoveAt(0);
contour.Add(currentEdge.Start);
var currentPoint = currentEdge.End;
var startPoint = currentEdge.Start;
LogManager.WriteLog($"轮廓起点: ({startPoint.X:F2}, {startPoint.Y:F2})");
// 连接后续的边
int maxIterations = remainingEdges.Count + 10; // 防止无限循环
int iteration = 0;
while (remainingEdges.Count > 0 && iteration < maxIterations)
{
iteration++;
var nextEdgeIndex = -1;
var tolerance = 0.01; // 1cm容差,稍微放宽
for (int i = 0; i < remainingEdges.Count; i++)
{
var edge = remainingEdges[i];
// 检查边的起点是否与当前点连接
if (Math.Abs(edge.Start.X - currentPoint.X) < tolerance &&
Math.Abs(edge.Start.Y - currentPoint.Y) < tolerance)
{
nextEdgeIndex = i;
currentPoint = edge.End;
break;
}
// 检查边的终点是否与当前点连接(反向)
else if (Math.Abs(edge.End.X - currentPoint.X) < tolerance &&
Math.Abs(edge.End.Y - currentPoint.Y) < tolerance)
{
nextEdgeIndex = i;
currentPoint = edge.Start;
break;
}
}
if (nextEdgeIndex >= 0)
{
contour.Add(currentPoint);
remainingEdges.RemoveAt(nextEdgeIndex);
// 检查是否回到起点(闭合轮廓)
if (Math.Abs(currentPoint.X - startPoint.X) < tolerance &&
Math.Abs(currentPoint.Y - startPoint.Y) < tolerance)
{
LogManager.WriteLog($"轮廓已闭合,点数: {contour.Count}");
break;
}
}
else
{
LogManager.WriteLog($"无法找到连接边,轮廓中断,点数: {contour.Count}");
break;
}
}
if (iteration >= maxIterations)
{
LogManager.WriteLog($"轮廓构建达到最大迭代次数,强制停止");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"构建单个轮廓失败: {ex.Message}");
}
return contour;
}
///
/// 从多个轮廓中获取最大的轮廓(外部边界)
///
/// 包含多个轮廓的点集合
/// 最大轮廓的点集合
private static List GetLargestContour(List allPoints)
{
var contours = new List>();
var currentContour = new List();
try
{
// 分离各个轮廓
foreach (var point in allPoints)
{
// 检查是否为分隔符
if (double.IsNaN(point.X) || double.IsNaN(point.Y))
{
if (currentContour.Count > 0)
{
contours.Add(new List(currentContour));
currentContour.Clear();
}
}
else
{
currentContour.Add(point);
}
}
// 添加最后一个轮廓
if (currentContour.Count > 0)
{
contours.Add(currentContour);
}
if (contours.Count == 0)
{
LogManager.WriteLog("未找到有效轮廓");
return allPoints;
}
// 找到最大的轮廓(按包围盒面积)
double maxArea = 0;
List largestContour = new List();
for (int i = 0; i < contours.Count; i++)
{
var contour = contours[i];
if (contour.Count >= 3)
{
var area = CalculateContourArea(contour);
LogManager.WriteLog($"轮廓 {i+1} 面积: {area:F2}, 点数: {contour.Count}");
if (area > maxArea)
{
maxArea = area;
largestContour = contour;
}
}
}
LogManager.WriteLog($"选择最大轮廓,面积: {maxArea:F2}, 原始点数: {largestContour.Count}");
// 清理和排序最大轮廓
var cleanedContour = CleanAndSortContour(largestContour);
LogManager.WriteLog($"清理后轮廓点数: {cleanedContour.Count}");
return cleanedContour;
}
catch (Exception ex)
{
LogManager.WriteLog($"获取最大轮廓失败: {ex.Message}");
return allPoints; // 返回原始点集合
}
}
///
/// 清理和排序轮廓点
///
/// 原始轮廓点
/// 清理和排序后的轮廓点
private static List CleanAndSortContour(List contour)
{
var result = new List();
try
{
if (contour.Count < 3)
{
LogManager.WriteLog($"轮廓点数不足: {contour.Count}");
return contour;
}
// 第1步:移除重复点
var uniquePoints = new List();
const double tolerance = 0.01; // 1cm容差
foreach (var point in contour)
{
bool isDuplicate = false;
foreach (var existing in uniquePoints)
{
if (Math.Abs(point.X - existing.X) < tolerance &&
Math.Abs(point.Y - existing.Y) < tolerance)
{
isDuplicate = true;
break;
}
}
if (!isDuplicate)
{
uniquePoints.Add(point);
}
}
LogManager.WriteLog($"去重后点数: {uniquePoints.Count}");
if (uniquePoints.Count < 3)
{
LogManager.WriteLog("去重后点数不足,返回原始轮廓");
return contour;
}
// 第2步:排序点以形成正确的轮廓
result = SortPointsIntoContour(uniquePoints);
LogManager.WriteLog($"排序后轮廓点数: {result.Count}");
for (int i = 0; i < result.Count; i++)
{
LogManager.WriteLog($" 排序点 {i}: ({result[i].X:F2}, {result[i].Y:F2})");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"清理轮廓失败: {ex.Message}");
return contour;
}
return result.Count >= 3 ? result : contour;
}
///
/// 将点排序成正确的轮廓顺序
///
/// 无序的点集合
/// 有序的轮廓点
private static List SortPointsIntoContour(List points)
{
var sortedPoints = new List();
try
{
if (points.Count < 3) return points;
// 找到最左下角的点作为起点(保证起点的唯一性)
var startPoint = points.OrderBy(p => p.X).ThenBy(p => p.Y).First();
sortedPoints.Add(startPoint);
var remainingPoints = new List(points);
remainingPoints.Remove(startPoint);
LogManager.WriteLog($"轮廓起始点: ({startPoint.X:F2}, {startPoint.Y:F2})");
// 使用最近邻算法按顺序连接点
var currentPoint = startPoint;
while (remainingPoints.Count > 0)
{
Point2D? nearestPoint = null;
double minDistance = double.MaxValue;
foreach (var point in remainingPoints)
{
var distance = Math.Sqrt(
Math.Pow(point.X - currentPoint.X, 2) +
Math.Pow(point.Y - currentPoint.Y, 2)
);
if (distance < minDistance)
{
minDistance = distance;
nearestPoint = point;
}
}
if (nearestPoint.HasValue)
{
sortedPoints.Add(nearestPoint.Value);
remainingPoints.Remove(nearestPoint.Value);
currentPoint = nearestPoint.Value;
LogManager.WriteLog($"下一个点: ({nearestPoint.Value.X:F2}, {nearestPoint.Value.Y:F2}), 距离: {minDistance:F2}");
}
else
{
LogManager.WriteLog("无法找到下一个最近点");
break;
}
}
// 验证轮廓是否闭合(可选)
if (sortedPoints.Count >= 3)
{
var firstPoint = sortedPoints[0];
var lastPoint = sortedPoints[sortedPoints.Count - 1];
var closingDistance = Math.Sqrt(
Math.Pow(lastPoint.X - firstPoint.X, 2) +
Math.Pow(lastPoint.Y - firstPoint.Y, 2)
);
LogManager.WriteLog($"轮廓闭合距离: {closingDistance:F2}");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"排序轮廓点失败: {ex.Message}");
return points;
}
return sortedPoints;
}
///
/// 计算轮廓的包围盒面积
///
/// 轮廓点集合
/// 包围盒面积
private static double CalculateContourArea(List contour)
{
if (contour.Count < 3) return 0;
try
{
var minX = contour.Min(p => p.X);
var maxX = contour.Max(p => p.X);
var minY = contour.Min(p => p.Y);
var maxY = contour.Max(p => p.Y);
return (maxX - minX) * (maxY - minY);
}
catch
{
return 0;
}
}
}
///
/// 片段信息类
///
public class FragmentInfo
{
public ComApi.InwOaFragment3 Fragment { get; set; }
public ComApi.InwLTransform3f3 Transform { get; set; }
public string PathKey { get; set; }
}
///
/// 优化的几何回调处理器
///
public class OptimizedGeometryCallback : ComApi.InwSimplePrimitivesCB
{
private List _triangles = new List();
private ComApi.InwLTransform3f3 _transform;
private double[] _transformMatrix;
public OptimizedGeometryCallback(ComApi.InwLTransform3f3 transform)
{
_transform = transform;
// 预先转换变换矩阵以提高性能
if (_transform != null)
{
try
{
var matrixArray = (Array)(object)_transform.Matrix;
_transformMatrix = matrixArray.ToArray();
}
catch (Exception ex)
{
LogManager.WriteLog($"转换变换矩阵失败: {ex.Message}");
_transformMatrix = null;
}
}
}
public void Line(ComApi.InwSimpleVertex v1, ComApi.InwSimpleVertex v2)
{
// 线段处理(如果需要)
}
public void Point(ComApi.InwSimpleVertex v1)
{
// 点处理(如果需要)
}
public void SnapPoint(ComApi.InwSimpleVertex v1)
{
// 捕捉点处理(如果需要)
}
public void Triangle(ComApi.InwSimpleVertex v1, ComApi.InwSimpleVertex v2, ComApi.InwSimpleVertex v3)
{
try
{
// 使用优化的数组访问方法
var coords1 = ((Array)(object)v1.coord).ToArray();
var coords2 = ((Array)(object)v2.coord).ToArray();
var coords3 = ((Array)(object)v3.coord).ToArray();
// 创建局部坐标点
var localPoint1 = new Point3D(coords1[0], coords1[1], coords1[2]);
var localPoint2 = new Point3D(coords2[0], coords2[1], coords2[2]);
var localPoint3 = new Point3D(coords3[0], coords3[1], coords3[2]);
// 应用变换矩阵转换为世界坐标
var worldPoint1 = TransformPoint(localPoint1);
var worldPoint2 = TransformPoint(localPoint2);
var worldPoint3 = TransformPoint(localPoint3);
// 创建三角形
var triangle = new Triangle3D(worldPoint1, worldPoint2, worldPoint3);
_triangles.Add(triangle);
}
catch (Exception ex)
{
LogManager.WriteLog($"处理三角形失败: {ex.Message}");
}
}
///
/// 将局部坐标点转换为世界坐标点
///
/// 局部坐标点
/// 世界坐标点
private Point3D TransformPoint(Point3D localPoint)
{
if (_transformMatrix == null)
{
return localPoint; // 如果没有变换矩阵,返回原始点
}
try
{
// 应用变换矩阵 (4x4 矩阵,列主序)
double x = localPoint.X;
double y = localPoint.Y;
double z = localPoint.Z;
double w = 1.0;
double newX = _transformMatrix[0] * x + _transformMatrix[4] * y + _transformMatrix[8] * z + _transformMatrix[12] * w;
double newY = _transformMatrix[1] * x + _transformMatrix[5] * y + _transformMatrix[9] * z + _transformMatrix[13] * w;
double newZ = _transformMatrix[2] * x + _transformMatrix[6] * y + _transformMatrix[10] * z + _transformMatrix[14] * w;
double newW = _transformMatrix[3] * x + _transformMatrix[7] * y + _transformMatrix[11] * z + _transformMatrix[15] * w;
// 透视除法(如果需要)
if (Math.Abs(newW) > 1e-10)
{
newX /= newW;
newY /= newW;
newZ /= newW;
}
return new Point3D(newX, newY, newZ);
}
catch (Exception ex)
{
LogManager.WriteLog($"坐标变换失败: {ex.Message}");
return localPoint;
}
}
///
/// 获取提取的三角形集合
///
/// 三角形集合
public List GetTriangles()
{
return _triangles;
}
}
///
/// 数组扩展方法(性能优化)
///
public static class ArrayExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] ToArray(this Array arr) where T : struct
{
T[] result = new T[arr.Length];
Array.Copy(arr, result, result.Length);
return result;
}
}
///
/// 三角形结构体
///
public struct Triangle3D
{
public Point3D Point1 { get; }
public Point3D Point2 { get; }
public Point3D Point3 { get; }
public Triangle3D(Point3D point1, Point3D point2, Point3D point3)
{
Point1 = point1;
Point2 = point2;
Point3 = point3;
}
public override string ToString()
{
return $"Triangle[{Point1}, {Point2}, {Point3}]";
}
}
///
/// 2D点结构体
///
public struct Point2D
{
public double X { get; }
public double Y { get; }
public Point2D(double x, double y)
{
X = x;
Y = y;
}
public override string ToString()
{
return $"Point2D({X:F3}, {Y:F3})";
}
}
///
/// 2D边结构体
///
public struct Edge2D
{
public Point2D Start { get; }
public Point2D End { get; }
public Edge2D(Point2D start, Point2D end)
{
Start = start;
End = end;
}
public string GetKey()
{
return $"{Start.X:F6},{Start.Y:F6}-{End.X:F6},{End.Y:F6}";
}
public string GetReverseKey()
{
return $"{End.X:F6},{End.Y:F6}-{Start.X:F6},{Start.Y:F6}";
}
public override string ToString()
{
return $"Edge2D[{Start} -> {End}]";
}
}
}