NavisworksTransport/GeometryExtractor.cs

1029 lines
38 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// 几何提取器 - 使用改进的算法和性能优化
/// </summary>
public class GeometryExtractor
{
/// <summary>
/// 提取模型项的顶视图轮廓
/// </summary>
/// <param name="modelItem">模型项</param>
/// <param name="tolerance">容差</param>
/// <returns>轮廓点集合</returns>
public static List<Point3D> ExtractTopViewOutline(ModelItem modelItem, double tolerance = 0.5)
{
var points = new List<Point3D>();
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;
}
/// <summary>
/// 优化的三角形提取方法
/// </summary>
/// <param name="modelItem">模型项</param>
/// <returns>三角形集合</returns>
private static List<Triangle3D> ExtractTrianglesOptimized(ModelItem modelItem)
{
var triangles = new List<Triangle3D>();
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;
}
/// <summary>
/// 获取唯一的片段(解决多实例问题)
/// </summary>
/// <param name="selection">COM 选择</param>
/// <returns>唯一片段信息集合</returns>
private static List<FragmentInfo> GetUniqueFragments(ComApi.InwOpSelection selection)
{
var fragmentMap = new Dictionary<string, FragmentInfo>();
try
{
foreach (ComApi.InwOaPath3 path in selection.Paths())
{
try
{
foreach (ComApi.InwOaFragment3 fragment in path.Fragments())
{
try
{
// 获取片段的唯一标识
var pathArray = ((Array)fragment.path.ArrayData).ToArray<int>();
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();
}
/// <summary>
/// 从三角形生成轮廓
/// </summary>
/// <param name="triangles">三角形集合</param>
/// <param name="tolerance">容差</param>
/// <returns>轮廓点集合</returns>
private static List<Point3D> GenerateOutlineFromTriangles(List<Triangle3D> triangles, double tolerance)
{
var outlinePoints = new List<Point3D>();
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<Edge2D>();
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;
}
/// <summary>
/// 查找边界边(在俯视图中只出现一次的边)
/// </summary>
/// <param name="edges">所有边的集合</param>
/// <returns>边界边集合</returns>
private static List<Edge2D> FindBoundaryEdges(List<Edge2D> edges)
{
var boundaryEdges = new List<Edge2D>();
var edgeCount = new Dictionary<string, int>();
var edgeMap = new Dictionary<string, Edge2D>();
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;
}
/// <summary>
/// 分析边界边的连通性
/// </summary>
/// <param name="boundaryEdges">边界边集合</param>
/// <returns>连通性分析字符串</returns>
private static string AnalyzeBoundaryConnectivity(List<Edge2D> boundaryEdges)
{
try
{
var vertexConnectionCount = new Dictionary<string, int>();
// 统计每个顶点的连接数
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}";
}
}
/// <summary>
/// 从边界边构建轮廓点集合(支持多轮廓)
/// </summary>
/// <param name="edges">边界边集合</param>
/// <returns>轮廓点集合</returns>
private static List<Point2D> BuildOutlineFromEdges(List<Edge2D> edges)
{
var allOutlinePoints = new List<Point2D>();
var remainingEdges = new List<Edge2D>(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;
}
/// <summary>
/// 构建单个连续轮廓
/// </summary>
/// <param name="remainingEdges">剩余边集合(会被修改)</param>
/// <returns>单个轮廓的点集合</returns>
private static List<Point2D> BuildSingleContour(List<Edge2D> remainingEdges)
{
var contour = new List<Point2D>();
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;
}
/// <summary>
/// 从多个轮廓中获取最大的轮廓(外部边界)
/// </summary>
/// <param name="allPoints">包含多个轮廓的点集合</param>
/// <returns>最大轮廓的点集合</returns>
private static List<Point2D> GetLargestContour(List<Point2D> allPoints)
{
var contours = new List<List<Point2D>>();
var currentContour = new List<Point2D>();
try
{
// 分离各个轮廓
foreach (var point in allPoints)
{
// 检查是否为分隔符
if (double.IsNaN(point.X) || double.IsNaN(point.Y))
{
if (currentContour.Count > 0)
{
contours.Add(new List<Point2D>(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<Point2D> largestContour = new List<Point2D>();
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; // 返回原始点集合
}
}
/// <summary>
/// 清理和排序轮廓点
/// </summary>
/// <param name="contour">原始轮廓点</param>
/// <returns>清理和排序后的轮廓点</returns>
private static List<Point2D> CleanAndSortContour(List<Point2D> contour)
{
var result = new List<Point2D>();
try
{
if (contour.Count < 3)
{
LogManager.WriteLog($"轮廓点数不足: {contour.Count}");
return contour;
}
// 第1步移除重复点
var uniquePoints = new List<Point2D>();
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;
}
/// <summary>
/// 将点排序成正确的轮廓顺序
/// </summary>
/// <param name="points">无序的点集合</param>
/// <returns>有序的轮廓点</returns>
private static List<Point2D> SortPointsIntoContour(List<Point2D> points)
{
var sortedPoints = new List<Point2D>();
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<Point2D>(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;
}
/// <summary>
/// 计算轮廓的包围盒面积
/// </summary>
/// <param name="contour">轮廓点集合</param>
/// <returns>包围盒面积</returns>
private static double CalculateContourArea(List<Point2D> 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;
}
}
}
/// <summary>
/// 片段信息类
/// </summary>
public class FragmentInfo
{
public ComApi.InwOaFragment3 Fragment { get; set; }
public ComApi.InwLTransform3f3 Transform { get; set; }
public string PathKey { get; set; }
}
/// <summary>
/// 优化的几何回调处理器
/// </summary>
public class OptimizedGeometryCallback : ComApi.InwSimplePrimitivesCB
{
private List<Triangle3D> _triangles = new List<Triangle3D>();
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<double>();
}
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<float>();
var coords2 = ((Array)(object)v2.coord).ToArray<float>();
var coords3 = ((Array)(object)v3.coord).ToArray<float>();
// 创建局部坐标点
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}");
}
}
/// <summary>
/// 将局部坐标点转换为世界坐标点
/// </summary>
/// <param name="localPoint">局部坐标点</param>
/// <returns>世界坐标点</returns>
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;
}
}
/// <summary>
/// 获取提取的三角形集合
/// </summary>
/// <returns>三角形集合</returns>
public List<Triangle3D> GetTriangles()
{
return _triangles;
}
}
/// <summary>
/// 数组扩展方法(性能优化)
/// </summary>
public static class ArrayExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] ToArray<T>(this Array arr) where T : struct
{
T[] result = new T[arr.Length];
Array.Copy(arr, result, result.Length);
return result;
}
}
/// <summary>
/// 三角形结构体
/// </summary>
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}]";
}
}
/// <summary>
/// 2D点结构体
/// </summary>
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})";
}
}
/// <summary>
/// 2D边结构体
/// </summary>
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}]";
}
}
}