增加了几何体缓存文件支持
This commit is contained in:
parent
55fbcbdb48
commit
dba1f76f0a
@ -291,6 +291,7 @@
|
||||
<Compile Include="src\Utils\FloorDetector.cs" />
|
||||
<Compile Include="src\Utils\ModelItemAnalysisHelper.cs" />
|
||||
<Compile Include="src\Utils\GeometryHelper.cs" />
|
||||
<Compile Include="src\Utils\GeometryCacheManager.cs" />
|
||||
<Compile Include="src\Utils\LogManager.cs" />
|
||||
<Compile Include="src\Utils\NavisworksApiHelper.cs" />
|
||||
<Compile Include="src\Utils\NavisworksSelectionHelper.cs" />
|
||||
@ -298,6 +299,7 @@
|
||||
<Compile Include="src\Utils\UnitsConverter.cs" />
|
||||
<Compile Include="src\Utils\VisibilityHelper.cs" />
|
||||
<Compile Include="src\Utils\ModelItemTransformHelper.cs" />
|
||||
<Compile Include="src\Utils\CachedTriangle3D.cs" />
|
||||
|
||||
<!-- Assembly Info -->
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
||||
@ -145,7 +145,32 @@ namespace NavisworksTransport.PathPlanning
|
||||
LogManager.Info("开始提取障碍物几何体...");
|
||||
var geometryStopwatch = Stopwatch.StartNew();
|
||||
|
||||
DMesh3 obstacleMesh = NavisworksToDMesh3Converter.ConvertFromModelItems(filteredItems);
|
||||
// 使用几何体缓存
|
||||
DMesh3 obstacleMesh = null;
|
||||
var cacheManager = new GeometryCacheManager(Application.ActiveDocument.FileName);
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[体素网格] 从缓存中提取 {filteredItems.Count} 个过滤后项的几何体");
|
||||
var allTriangles = new List<Triangle3D>();
|
||||
|
||||
int processedItems = 0;
|
||||
foreach (var item in filteredItems)
|
||||
{
|
||||
var itemTriangles = cacheManager.GetTrianglesForModelItem(item);
|
||||
allTriangles.AddRange(itemTriangles);
|
||||
processedItems++;
|
||||
}
|
||||
|
||||
LogManager.Info($"[体素网格] 从缓存中提取完成,总三角形数: {allTriangles.Count}");
|
||||
obstacleMesh = NavisworksToDMesh3Converter.Convert(allTriangles);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[体素网格] 使用几何体缓存失败: {ex.Message},回退到传统方法");
|
||||
|
||||
// 如果缓存不可用,则使用传统方法提取几何体
|
||||
obstacleMesh = NavisworksToDMesh3Converter.ConvertFromModelItems(filteredItems);
|
||||
}
|
||||
|
||||
geometryStopwatch.Stop();
|
||||
LogManager.Info($"几何体提取完成,耗时: {geometryStopwatch.ElapsedMilliseconds} ms");
|
||||
|
||||
82
src/Utils/CachedTriangle3D.cs
Normal file
82
src/Utils/CachedTriangle3D.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using Autodesk.Navisworks.Api;
|
||||
|
||||
namespace NavisworksTransport
|
||||
{
|
||||
/// <summary>
|
||||
/// 可序列化的点结构体
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[System.Xml.Serialization.XmlType("CachedPoint3D")]
|
||||
public struct CachedPoint3D
|
||||
{
|
||||
[System.Xml.Serialization.XmlAttribute("X")]
|
||||
public double X { get; set; }
|
||||
|
||||
[System.Xml.Serialization.XmlAttribute("Y")]
|
||||
public double Y { get; set; }
|
||||
|
||||
[System.Xml.Serialization.XmlAttribute("Z")]
|
||||
public double Z { get; set; }
|
||||
|
||||
public CachedPoint3D(double x, double y, double z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
public CachedPoint3D(Point3D point)
|
||||
{
|
||||
X = point.X;
|
||||
Y = point.Y;
|
||||
Z = point.Z;
|
||||
}
|
||||
|
||||
public Point3D ToNavisworksPoint3D()
|
||||
{
|
||||
return new Point3D(X, Y, Z);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Point3D({X:F3}, {Y:F3}, {Z:F3})";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 可序列化的三角形结构体
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[System.Xml.Serialization.XmlType("CachedTriangle3D")]
|
||||
public struct CachedTriangle3D
|
||||
{
|
||||
[System.Xml.Serialization.XmlElement("Point1")]
|
||||
public CachedPoint3D Point1 { get; set; }
|
||||
|
||||
[System.Xml.Serialization.XmlElement("Point2")]
|
||||
public CachedPoint3D Point2 { get; set; }
|
||||
|
||||
[System.Xml.Serialization.XmlElement("Point3")]
|
||||
public CachedPoint3D Point3 { get; set; }
|
||||
|
||||
public CachedTriangle3D(CachedPoint3D point1, CachedPoint3D point2, CachedPoint3D point3)
|
||||
{
|
||||
Point1 = point1;
|
||||
Point2 = point2;
|
||||
Point3 = point3;
|
||||
}
|
||||
|
||||
public CachedTriangle3D(Point3D point1, Point3D point2, Point3D point3)
|
||||
{
|
||||
Point1 = new CachedPoint3D(point1);
|
||||
Point2 = new CachedPoint3D(point2);
|
||||
Point3 = new CachedPoint3D(point3);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Triangle[{Point1}, {Point2}, {Point3}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
631
src/Utils/GeometryCacheManager.cs
Normal file
631
src/Utils/GeometryCacheManager.cs
Normal file
@ -0,0 +1,631 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using ComApi = Autodesk.Navisworks.Api.Interop.ComApi;
|
||||
using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
|
||||
|
||||
namespace NavisworksTransport.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 几何体缓存管理器
|
||||
/// 用于缓存模型文档中的几何体信息,提高访问性能
|
||||
/// </summary>
|
||||
public class GeometryCacheManager
|
||||
{
|
||||
// 缓存根节点
|
||||
private PathTreeNode cacheRoot;
|
||||
|
||||
// 当前文档路径
|
||||
private string documentPath;
|
||||
|
||||
// 缓存文件路径
|
||||
private string cacheFilePath;
|
||||
|
||||
// 缓存加载状态
|
||||
private bool _isCacheLoaded = false;
|
||||
private bool _cacheLoadResult = false;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="docPath">文档路径</param>
|
||||
public GeometryCacheManager(string docPath)
|
||||
{
|
||||
documentPath = docPath;
|
||||
cacheRoot = new PathTreeNode("", "");
|
||||
|
||||
// 生成缓存文件路径
|
||||
var docDir = Path.GetDirectoryName(documentPath);
|
||||
var docName = Path.GetFileNameWithoutExtension(documentPath);
|
||||
cacheFilePath = Path.Combine(docDir, $"{docName}.geometrycache");
|
||||
|
||||
LogManager.Info($"[几何体缓存] 缓存文件路径: {cacheFilePath}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从模型项列表提取所有片段并构建缓存
|
||||
/// </summary>
|
||||
/// <param name="modelItems">模型项列表</param>
|
||||
public void BuildCache(IEnumerable<ModelItem> modelItems)
|
||||
{
|
||||
var itemCount = modelItems?.Count() ?? 0;
|
||||
LogManager.Info($"[几何体缓存] 开始构建几何体缓存,模型项数量: {itemCount}");
|
||||
|
||||
// 清空现有缓存
|
||||
cacheRoot = new PathTreeNode("", "");
|
||||
|
||||
ComApi.InwOpSelection comSelection = null;
|
||||
try
|
||||
{
|
||||
// 转换为 COM 选择
|
||||
var modelCollection = new ModelItemCollection();
|
||||
foreach (var item in modelItems)
|
||||
{
|
||||
modelCollection.Add(item);
|
||||
}
|
||||
|
||||
comSelection = ComApiBridge.ToInwOpSelection(modelCollection);
|
||||
|
||||
// 获取所有片段
|
||||
var allFragments = GeometryHelper.GetAllFragments(comSelection);
|
||||
|
||||
int processedFragments = 0;
|
||||
int totalTriangles = 0;
|
||||
int skippedDuplicates = 0;
|
||||
|
||||
// 处理每个片段
|
||||
foreach (var fragmentInfo in allFragments)
|
||||
{
|
||||
try
|
||||
{
|
||||
var callback = new OptimizedGeometryCallback(fragmentInfo.TransformMatrix);
|
||||
fragmentInfo.Fragment.GenerateSimplePrimitives(
|
||||
ComApi.nwEVertexProperty.eNORMAL,
|
||||
callback);
|
||||
|
||||
var fragmentTriangles = callback.GetTriangles();
|
||||
totalTriangles += fragmentTriangles.Count;
|
||||
|
||||
// 创建缓存片段数据
|
||||
var cachedFragment = new CachedFragmentData
|
||||
{
|
||||
PathKey = fragmentInfo.PathKey,
|
||||
Triangles = fragmentTriangles.Select(t => new NavisworksTransport.CachedTriangle3D(t.Point1, t.Point2, t.Point3)).ToList()
|
||||
};
|
||||
|
||||
// 插入到树形结构中
|
||||
InsertFragment(fragmentInfo.PathKey, cachedFragment);
|
||||
|
||||
processedFragments++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[几何体缓存] 处理片段失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 统计最终缓存中的片段数量
|
||||
int totalCachedFragments = CountFragments(cacheRoot);
|
||||
LogManager.Info($"[几何体缓存] 几何体缓存构建完成,处理片段数: {processedFragments},总三角形数: {totalTriangles},最终缓存片段数: {totalCachedFragments},跳过重复: {skippedDuplicates}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 释放COM对象
|
||||
if (comSelection != null)
|
||||
{
|
||||
System.Runtime.InteropServices.Marshal.ReleaseComObject(comSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将片段插入到树形结构中
|
||||
/// </summary>
|
||||
/// <param name="pathKey">片段路径</param>
|
||||
/// <param name="fragment">片段数据</param>
|
||||
private void InsertFragment(string pathKey, CachedFragmentData fragment)
|
||||
{
|
||||
var pathParts = pathKey.Split(',');
|
||||
var currentNode = cacheRoot;
|
||||
|
||||
// 逐级创建或导航到目标节点
|
||||
for (int i = 0; i < pathParts.Length; i++)
|
||||
{
|
||||
var currentPath = string.Join(",", pathParts.Take(i + 1));
|
||||
var nodeKey = pathParts[i];
|
||||
|
||||
currentNode = currentNode.AddChild(nodeKey, currentPath);
|
||||
}
|
||||
|
||||
// 检查是否已存在相同PathKey的片段(避免完全重复)
|
||||
bool isDuplicate = currentNode.Fragments.Any(f => f.PathKey == pathKey &&
|
||||
f.Triangles.Count == fragment.Triangles.Count &&
|
||||
f.Triangles.SequenceEqual(fragment.Triangles, new CachedTriangleComparer()));
|
||||
|
||||
if (!isDuplicate)
|
||||
{
|
||||
// 只有当片段不完全相同时才添加
|
||||
currentNode.Fragments.Add(fragment);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Debug($"[几何体缓存] 跳过重复片段,PathKey: {pathKey}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定ModelItem的所有三角形数据
|
||||
/// 如果缓存不存在,则自动生成缓存
|
||||
/// </summary>
|
||||
/// <param name="modelItem">模型项</param>
|
||||
/// <returns>三角形列表</returns>
|
||||
public List<Triangle3D> GetTrianglesForModelItem(ModelItem modelItem)
|
||||
{
|
||||
// 确保缓存已加载(只加载一次)
|
||||
if (!_isCacheLoaded)
|
||||
{
|
||||
if (CacheExists())
|
||||
{
|
||||
_cacheLoadResult = LoadCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info("[几何体缓存] 缓存不存在,开始自动生成缓存...");
|
||||
GenerateCacheAutomatically();
|
||||
// 重新尝试加载新生成的缓存
|
||||
if (CacheExists())
|
||||
{
|
||||
_cacheLoadResult = LoadCache();
|
||||
}
|
||||
}
|
||||
_isCacheLoaded = true;
|
||||
}
|
||||
|
||||
// 如果缓存加载失败,则使用传统方法
|
||||
if (!_cacheLoadResult)
|
||||
{
|
||||
LogManager.Warning("[几何体缓存] 无法加载缓存,使用传统方法提取几何体");
|
||||
return GeometryHelper.ExtractTriangles(new[] { modelItem });
|
||||
}
|
||||
|
||||
var result = new List<Triangle3D>();
|
||||
|
||||
// 获取ModelItem的所有路径
|
||||
var itemPaths = GetModelItemPaths(modelItem);
|
||||
|
||||
// 收集所有路径下的片段
|
||||
foreach (var pathKey in itemPaths)
|
||||
{
|
||||
var fragments = GetFragmentsForPath(pathKey);
|
||||
foreach (var fragment in fragments)
|
||||
{
|
||||
// 将CachedTriangle3D转换为Triangle3D
|
||||
foreach (var cachedTriangle in fragment.Triangles)
|
||||
{
|
||||
result.Add(new Triangle3D(
|
||||
cachedTriangle.Point1.ToNavisworksPoint3D(),
|
||||
cachedTriangle.Point2.ToNavisworksPoint3D(),
|
||||
cachedTriangle.Point3.ToNavisworksPoint3D()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定ModelItem的所有三角形数据(自动缓存版本)
|
||||
/// 如果缓存不存在,则自动生成缓存
|
||||
/// </summary>
|
||||
/// <param name="modelItem">模型项</param>
|
||||
/// <returns>三角形列表</returns>
|
||||
public List<Triangle3D> GetTrianglesForModelItemWithAutoCache(ModelItem modelItem)
|
||||
{
|
||||
// 检查缓存是否存在,如果不存在则自动生成
|
||||
if (!CacheExists())
|
||||
{
|
||||
LogManager.Info("[几何体缓存] 缓存不存在,开始自动生成缓存...");
|
||||
GenerateCacheAutomatically();
|
||||
}
|
||||
|
||||
// 如果缓存仍然不存在或加载失败,则使用传统方法
|
||||
if (!CacheExists() || !LoadCache())
|
||||
{
|
||||
LogManager.Warning("[几何体缓存] 无法加载缓存,使用传统方法提取几何体");
|
||||
return GeometryHelper.ExtractTriangles(new[] { modelItem });
|
||||
}
|
||||
|
||||
return GetTrianglesForModelItem(modelItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归统计缓存中的片段数量
|
||||
/// </summary>
|
||||
/// <param name="node">当前节点</param>
|
||||
/// <returns>片段总数</returns>
|
||||
private int CountFragments(PathTreeNode node)
|
||||
{
|
||||
if (node == null) return 0;
|
||||
|
||||
int count = node.Fragments?.Count ?? 0;
|
||||
|
||||
if (node.Children != null)
|
||||
{
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
count += CountFragments(child);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取ModelItem的所有路径
|
||||
/// </summary>
|
||||
/// <param name="modelItem">模型项</param>
|
||||
/// <returns>路径列表</returns>
|
||||
private List<string> GetModelItemPaths(ModelItem modelItem)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
// 转换为COM选择
|
||||
var modelCollection = new ModelItemCollection();
|
||||
modelCollection.Add(modelItem);
|
||||
var comSelection = ComApiBridge.ToInwOpSelection(modelCollection);
|
||||
|
||||
// 遍历所有路径
|
||||
foreach (ComApi.InwOaPath3 path in comSelection.Paths())
|
||||
{
|
||||
var pathArray = ((Array)path.ArrayData).ToArray<int>();
|
||||
var pathKey = string.Join(",", pathArray);
|
||||
paths.Add(pathKey);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定路径下的所有片段
|
||||
/// </summary>
|
||||
/// <param name="targetPath">目标路径</param>
|
||||
/// <returns>片段列表</returns>
|
||||
private List<CachedFragmentData> GetFragmentsForPath(string targetPath)
|
||||
{
|
||||
var result = new List<CachedFragmentData>();
|
||||
var pathParts = targetPath.Split(',');
|
||||
var currentNode = cacheRoot;
|
||||
|
||||
// 逐级导航到目标节点
|
||||
for (int i = 0; i < pathParts.Length; i++)
|
||||
{
|
||||
var nodeKey = pathParts[i];
|
||||
var childNode = currentNode.FindChild(nodeKey);
|
||||
if (childNode != null)
|
||||
{
|
||||
currentNode = childNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 路径不存在,返回空结果
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 只返回目标节点的片段
|
||||
if (currentNode.Fragments != null)
|
||||
{
|
||||
result.AddRange(currentNode.Fragments);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存缓存到文件
|
||||
/// </summary>
|
||||
public void SaveCache()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 统计缓存中的数据量
|
||||
int fragmentCount = 0;
|
||||
int nodeCount = 0;
|
||||
CountCacheNodes(cacheRoot, ref fragmentCount, ref nodeCount);
|
||||
|
||||
LogManager.Info($"[几何体缓存] 保存缓存到文件: {cacheFilePath},节点数: {nodeCount}, 片段数: {fragmentCount}");
|
||||
|
||||
// 使用XML序列化
|
||||
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(PathTreeNode));
|
||||
using (var writer = new System.IO.StreamWriter(cacheFilePath, false, System.Text.Encoding.UTF8))
|
||||
{
|
||||
serializer.Serialize(writer, cacheRoot);
|
||||
}
|
||||
|
||||
// 检查文件是否成功创建
|
||||
if (File.Exists(cacheFilePath))
|
||||
{
|
||||
var fileInfo = new FileInfo(cacheFilePath);
|
||||
LogManager.Info($"[几何体缓存] 缓存保存完成,文件大小: {fileInfo.Length} 字节");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"[几何体缓存] 缓存保存完成,但文件未找到: {cacheFilePath}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[几何体缓存] 保存缓存失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从文件加载缓存
|
||||
/// </summary>
|
||||
/// <returns>是否加载成功</returns>
|
||||
public bool LoadCache()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(cacheFilePath))
|
||||
{
|
||||
LogManager.Info($"[几何体缓存] 缓存文件不存在: {cacheFilePath}");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogManager.Info($"[几何体缓存] 从文件加载缓存: {cacheFilePath}");
|
||||
|
||||
// 使用XML反序列化
|
||||
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(PathTreeNode));
|
||||
using (var reader = new System.IO.StreamReader(cacheFilePath, System.Text.Encoding.UTF8))
|
||||
{
|
||||
cacheRoot = (PathTreeNode)serializer.Deserialize(reader);
|
||||
}
|
||||
|
||||
// 统计缓存中的数据量
|
||||
int fragmentCount = 0;
|
||||
int nodeCount = 0;
|
||||
CountCacheNodes(cacheRoot, ref fragmentCount, ref nodeCount);
|
||||
|
||||
LogManager.Info($"[几何体缓存] 缓存加载完成,节点数: {nodeCount}, 片段数: {fragmentCount}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[几何体缓存] 加载缓存失败: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归统计缓存中的节点和片段数量
|
||||
/// </summary>
|
||||
private void CountCacheNodes(PathTreeNode node, ref int fragmentCount, ref int nodeCount)
|
||||
{
|
||||
if (node == null) return;
|
||||
|
||||
nodeCount++;
|
||||
fragmentCount += node.Fragments?.Count ?? 0;
|
||||
|
||||
if (node.Children != null)
|
||||
{
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
CountCacheNodes(child, ref fragmentCount, ref nodeCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查缓存文件是否存在
|
||||
/// </summary>
|
||||
/// <returns>是否存在</returns>
|
||||
public bool CacheExists()
|
||||
{
|
||||
bool exists = File.Exists(cacheFilePath);
|
||||
LogManager.Info($"[几何体缓存] 检查缓存文件是否存在: {cacheFilePath}, 结果: {(exists ? "存在" : "不存在")}");
|
||||
return exists;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动生成缓存文件
|
||||
/// </summary>
|
||||
private void GenerateCacheAutomatically()
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("[几何体缓存] 开始自动生成缓存文件");
|
||||
|
||||
// 获取当前文档
|
||||
var document = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||
if (document == null)
|
||||
{
|
||||
LogManager.Error("[几何体缓存] 无法获取活动文档");
|
||||
return;
|
||||
}
|
||||
|
||||
// 开始进度条
|
||||
var progress = Autodesk.Navisworks.Api.Application.BeginProgress("生成几何体缓存",
|
||||
$"正在为 {Path.GetFileName(document.FileName)} 生成几何体缓存...");
|
||||
|
||||
try
|
||||
{
|
||||
// 收集场景中所有带几何信息的对象
|
||||
var allModelItems = GetAllModelItems(document);
|
||||
LogManager.Info($"[几何体缓存] 场景中共有 {allModelItems.Count} 个带几何信息的模型对象");
|
||||
|
||||
if (allModelItems.Count == 0)
|
||||
{
|
||||
LogManager.Warning("[几何体缓存] 场景中没有找到任何带几何信息的模型对象");
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新进度
|
||||
progress.Update(0.25); // 只传递进度值,不传递消息
|
||||
|
||||
// 构建缓存
|
||||
BuildCache(allModelItems);
|
||||
|
||||
// 更新进度
|
||||
progress.Update(0.75); // 只传递进度值,不传递消息
|
||||
|
||||
// 保存缓存到文件
|
||||
SaveCache();
|
||||
|
||||
// 更新进度
|
||||
progress.Update(1.0); // 只传递进度值,不传递消息
|
||||
|
||||
LogManager.Info("[几何体缓存] 几何体缓存自动生成完成");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 确保进度条被关闭
|
||||
Autodesk.Navisworks.Api.Application.EndProgress();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[几何体缓存] 自动生成缓存失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取场景中所有带几何信息的模型对象
|
||||
/// </summary>
|
||||
private List<ModelItem> GetAllModelItems(Autodesk.Navisworks.Api.Document document)
|
||||
{
|
||||
var items = new List<ModelItem>();
|
||||
|
||||
// 遍历文档中的所有模型
|
||||
foreach (var model in document.Models)
|
||||
{
|
||||
if (model.RootItem != null)
|
||||
{
|
||||
CollectAllItems(model.RootItem, items);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归收集所有带几何信息的对象
|
||||
/// </summary>
|
||||
private void CollectAllItems(ModelItem item, List<ModelItem> result)
|
||||
{
|
||||
// 如果当前对象有几何信息,加入结果
|
||||
if (item.HasGeometry)
|
||||
{
|
||||
result.Add(item);
|
||||
}
|
||||
|
||||
// 递归处理所有子对象
|
||||
foreach (var child in item.Children)
|
||||
{
|
||||
CollectAllItems(child, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 路径树节点
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PathTreeNode
|
||||
{
|
||||
public string NodeKey { get; set; }
|
||||
public string FullPath { get; set; }
|
||||
public List<CachedFragmentData> Fragments { get; set; }
|
||||
|
||||
// 使用List存储子节点,避免Dictionary序列化问题
|
||||
public List<PathTreeNode> Children { get; set; }
|
||||
|
||||
// 用于查找子节点的辅助方法
|
||||
public PathTreeNode FindChild(string nodeKey)
|
||||
{
|
||||
return Children?.FirstOrDefault(child => child.NodeKey == nodeKey);
|
||||
}
|
||||
|
||||
// 用于添加子节点的辅助方法
|
||||
public PathTreeNode AddChild(string nodeKey, string fullPath)
|
||||
{
|
||||
if (Children == null)
|
||||
Children = new List<PathTreeNode>();
|
||||
|
||||
var existingChild = FindChild(nodeKey);
|
||||
if (existingChild != null)
|
||||
return existingChild;
|
||||
|
||||
var newChild = new PathTreeNode
|
||||
{
|
||||
NodeKey = nodeKey,
|
||||
FullPath = fullPath,
|
||||
Fragments = new List<CachedFragmentData>(),
|
||||
Children = new List<PathTreeNode>()
|
||||
};
|
||||
|
||||
Children.Add(newChild);
|
||||
return newChild;
|
||||
}
|
||||
|
||||
public PathTreeNode()
|
||||
{
|
||||
Fragments = new List<CachedFragmentData>();
|
||||
Children = new List<PathTreeNode>();
|
||||
}
|
||||
|
||||
public PathTreeNode(string nodeKey, string fullPath)
|
||||
{
|
||||
NodeKey = nodeKey;
|
||||
FullPath = fullPath;
|
||||
Fragments = new List<CachedFragmentData>();
|
||||
Children = new List<PathTreeNode>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存片段数据
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[System.Xml.Serialization.XmlType("CachedFragmentData")]
|
||||
public class CachedFragmentData
|
||||
{
|
||||
[System.Xml.Serialization.XmlAttribute("PathKey")]
|
||||
public string PathKey { get; set; }
|
||||
|
||||
[System.Xml.Serialization.XmlArray("Triangles")]
|
||||
[System.Xml.Serialization.XmlArrayItem("Triangle")]
|
||||
public List<CachedTriangle3D> Triangles { get; set; }
|
||||
|
||||
public CachedFragmentData()
|
||||
{
|
||||
Triangles = new List<CachedTriangle3D>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 三角形比较器,用于检测重复的三角形数据
|
||||
/// </summary>
|
||||
public class CachedTriangleComparer : IEqualityComparer<CachedTriangle3D>
|
||||
{
|
||||
public bool Equals(CachedTriangle3D x, CachedTriangle3D y)
|
||||
{
|
||||
if (x.Point1.X != y.Point1.X || x.Point1.Y != y.Point1.Y || x.Point1.Z != y.Point1.Z)
|
||||
return false;
|
||||
if (x.Point2.X != y.Point2.X || x.Point2.Y != y.Point2.Y || x.Point2.Z != y.Point2.Z)
|
||||
return false;
|
||||
if (x.Point3.X != y.Point3.X || x.Point3.Y != y.Point3.Y || x.Point3.Z != y.Point3.Z)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetHashCode(CachedTriangle3D obj)
|
||||
{
|
||||
// 简单的哈希实现
|
||||
return obj.Point1.GetHashCode() ^ obj.Point2.GetHashCode() ^ obj.Point3.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,7 @@ using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
|
||||
namespace NavisworksTransport
|
||||
{
|
||||
/// <summary>
|
||||
/// 几何提取器 - 使用改进的算法和性能优化
|
||||
/// 几何提取器
|
||||
/// </summary>
|
||||
public class GeometryHelper
|
||||
{
|
||||
@ -291,14 +291,12 @@ namespace NavisworksTransport
|
||||
}
|
||||
}
|
||||
|
||||
// 使用递增索引作为唯一标识,确保每个片段都被处理
|
||||
var uniqueKey = $"fragment_{totalFragmentCount}";
|
||||
|
||||
// 使用实际的路径键而不是递增索引
|
||||
fragmentList.Add(new FragmentInfo
|
||||
{
|
||||
Fragment = fragment,
|
||||
TransformMatrix = transformMatrix,
|
||||
PathKey = uniqueKey // 使用唯一索引而不是pathKey
|
||||
PathKey = pathKey // 使用实际的路径键
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1058,15 +1056,6 @@ namespace NavisworksTransport
|
||||
public OptimizedGeometryCallback(double[] transformMatrix)
|
||||
{
|
||||
_transformMatrix = transformMatrix;
|
||||
|
||||
if (_transformMatrix != null)
|
||||
{
|
||||
LogManager.Debug($"几何回调处理器使用预处理矩阵,元素数量: {_transformMatrix.Length}");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Debug("几何回调处理器使用单位矩阵(无变换)");
|
||||
}
|
||||
}
|
||||
|
||||
public void Line(ComApi.InwSimpleVertex v1, ComApi.InwSimpleVertex v2)
|
||||
|
||||
@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using NavisworksTransport.Utils;
|
||||
using g4;
|
||||
|
||||
namespace NavisworksTransport
|
||||
|
||||
Loading…
Reference in New Issue
Block a user