feat(voxel): 阶段1.4 - 测试 geometry4Sharp 的 MeshSignedDistanceGrid
- 创建 MeshSDFTester.cs: 测试 geometry4Sharp 库的可用性和功能 - 实现 Navisworks Triangle3D 到 DMesh3 的转换 - 实现 MeshSignedDistanceGrid (SDF) 计算功能 - 添加库可用性快速测试方法 - 手动构建测试立方体网格 特性(原型版本): - QuickLibraryTest(): 验证 geometry4Sharp 库是否正常工作 - ConvertToDMesh3(): 将 Navisworks 三角形转换为 DMesh3 格式 - ComputeSDF(): 计算签名距离场(使用 DMeshAABBTree3 加速) - TestFullPipeline(): 完整测试流程(ModelItem → 三角形 → DMesh3 → SDF) - CreateTestCubeMesh(): 手动创建测试立方体 注意: - 这是原型版本,部分 SDF 距离查询 API 需要进一步研究 - 验证了 DMesh3, DMeshAABBTree3, MeshSignedDistanceGrid 基本可用 - 与 GeometryHelper.ExtractTriangles() 集成 下一步: 体素可视化验证(阶段1.5)或根据实际需求调整
This commit is contained in:
parent
40946091dd
commit
f64e79d372
@ -195,6 +195,7 @@
|
||||
<Compile Include="src\PathPlanning\VoxelCell.cs" />
|
||||
<Compile Include="src\PathPlanning\VoxelGrid.cs" />
|
||||
<Compile Include="src\PathPlanning\VoxelGridGenerator.cs" />
|
||||
<Compile Include="src\PathPlanning\MeshSDFTester.cs" />
|
||||
|
||||
<!-- UI - WPF -->
|
||||
<Compile Include="src\UI\WPF\Views\LogisticsControlPanel.xaml.cs">
|
||||
|
||||
376
src/PathPlanning/MeshSDFTester.cs
Normal file
376
src/PathPlanning/MeshSDFTester.cs
Normal file
@ -0,0 +1,376 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using NavisworksTransport.Utils;
|
||||
using g4;
|
||||
|
||||
namespace NavisworksTransport.PathPlanning
|
||||
{
|
||||
/// <summary>
|
||||
/// Mesh SDF 测试器 - 测试 geometry4Sharp 的 MeshSignedDistanceGrid 功能
|
||||
/// 阶段 1.4:验证 Navisworks 网格到 DMesh3 的转换和 SDF 计算
|
||||
/// 注意:这是原型版本,部分API需要根据实际geometry4Sharp文档调整
|
||||
/// </summary>
|
||||
public class MeshSDFTester
|
||||
{
|
||||
/// <summary>
|
||||
/// 简单测试:验证 geometry4Sharp 是否可用
|
||||
/// </summary>
|
||||
public static void QuickLibraryTest()
|
||||
{
|
||||
LogManager.Info("=== geometry4Sharp 库可用性测试 ===");
|
||||
|
||||
try
|
||||
{
|
||||
// 测试创建 DMesh3
|
||||
var mesh = new DMesh3(MeshComponents.None);
|
||||
LogManager.Info($"✅ DMesh3 创建成功");
|
||||
|
||||
// 添加简单的三角形
|
||||
int v0 = mesh.AppendVertex(new Vector3d(0, 0, 0));
|
||||
int v1 = mesh.AppendVertex(new Vector3d(1, 0, 0));
|
||||
int v2 = mesh.AppendVertex(new Vector3d(0, 1, 0));
|
||||
int t0 = mesh.AppendTriangle(v0, v1, v2);
|
||||
|
||||
LogManager.Info($"✅ 顶点和三角形添加成功: {mesh.VertexCount} 顶点, {mesh.TriangleCount} 三角形");
|
||||
|
||||
// 测试 AABB 树
|
||||
var spatial = new DMeshAABBTree3(mesh, autoBuild: true);
|
||||
LogManager.Info($"✅ DMeshAABBTree3 创建成功");
|
||||
|
||||
LogManager.Info("=== geometry4Sharp 库测试通过 ===");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"❌ geometry4Sharp 库测试失败: {ex.Message}");
|
||||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 将 Navisworks 三角形转换为 geometry4Sharp DMesh3
|
||||
/// </summary>
|
||||
/// <param name="triangles">Navisworks 三角形集合</param>
|
||||
/// <returns>DMesh3 对象</returns>
|
||||
public static DMesh3 ConvertToDMesh3(List<Triangle3D> triangles)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
LogManager.Info("=== 开始转换 Navisworks 网格到 DMesh3 ===");
|
||||
|
||||
var mesh = new DMesh3(MeshComponents.None); // 不需要法线、颜色等额外组件
|
||||
|
||||
try
|
||||
{
|
||||
// 第一步:添加所有顶点(使用字典去重)
|
||||
var vertexMap = new Dictionary<string, int>();
|
||||
int vertexCount = 0;
|
||||
|
||||
foreach (var triangle in triangles)
|
||||
{
|
||||
AddVertexIfNotExists(mesh, triangle.Point1, vertexMap, ref vertexCount);
|
||||
AddVertexIfNotExists(mesh, triangle.Point2, vertexMap, ref vertexCount);
|
||||
AddVertexIfNotExists(mesh, triangle.Point3, vertexMap, ref vertexCount);
|
||||
}
|
||||
|
||||
LogManager.Info($"顶点添加完成: {mesh.VertexCount} 个顶点");
|
||||
|
||||
// 第二步:添加所有三角形面
|
||||
int triangleAddedCount = 0;
|
||||
int triangleFailedCount = 0;
|
||||
|
||||
foreach (var triangle in triangles)
|
||||
{
|
||||
try
|
||||
{
|
||||
int v1 = GetVertexIndex(triangle.Point1, vertexMap);
|
||||
int v2 = GetVertexIndex(triangle.Point2, vertexMap);
|
||||
int v3 = GetVertexIndex(triangle.Point3, vertexMap);
|
||||
|
||||
if (v1 >= 0 && v2 >= 0 && v3 >= 0 && v1 != v2 && v2 != v3 && v1 != v3)
|
||||
{
|
||||
int tid = mesh.AppendTriangle(v1, v2, v3);
|
||||
if (tid >= 0)
|
||||
{
|
||||
triangleAddedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
triangleFailedCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
triangleFailedCount++;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
triangleFailedCount++;
|
||||
LogManager.Debug($"添加三角形失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
LogManager.Info($"三角形添加完成: 成功={triangleAddedCount}, 失败={triangleFailedCount}");
|
||||
|
||||
// 第三步:网格验证和修复
|
||||
if (!mesh.IsClosed())
|
||||
{
|
||||
LogManager.Warning("网格不闭合,可能影响 SDF 计算准确性");
|
||||
}
|
||||
|
||||
// 计算边界框
|
||||
var bounds = mesh.CachedBounds;
|
||||
LogManager.Info($"网格边界: Min=({bounds.Min.x:F2}, {bounds.Min.y:F2}, {bounds.Min.z:F2}), " +
|
||||
$"Max=({bounds.Max.x:F2}, {bounds.Max.y:F2}, {bounds.Max.z:F2})");
|
||||
|
||||
stopwatch.Stop();
|
||||
LogManager.Info($"=== DMesh3 转换完成 ===");
|
||||
LogManager.Info($"转换耗时: {stopwatch.ElapsedMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds:F2} 秒)");
|
||||
LogManager.Info($"网格统计: 顶点={mesh.VertexCount}, 三角形={mesh.TriangleCount}, 边={mesh.EdgeCount}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"转换到 DMesh3 失败: {ex.Message}");
|
||||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加顶点(如果不存在)
|
||||
/// </summary>
|
||||
private static void AddVertexIfNotExists(DMesh3 mesh, Point3D point, Dictionary<string, int> vertexMap, ref int vertexCount)
|
||||
{
|
||||
string key = GetVertexKey(point);
|
||||
|
||||
if (!vertexMap.ContainsKey(key))
|
||||
{
|
||||
int vid = mesh.AppendVertex(new Vector3d(point.X, point.Y, point.Z));
|
||||
vertexMap[key] = vid;
|
||||
vertexCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取顶点索引
|
||||
/// </summary>
|
||||
private static int GetVertexIndex(Point3D point, Dictionary<string, int> vertexMap)
|
||||
{
|
||||
string key = GetVertexKey(point);
|
||||
return vertexMap.TryGetValue(key, out int index) ? index : -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成顶点键(用于去重)
|
||||
/// </summary>
|
||||
private static string GetVertexKey(Point3D point, double tolerance = 0.0001)
|
||||
{
|
||||
// 使用较高精度避免过度合并
|
||||
return $"{Math.Round(point.X / tolerance) * tolerance:F6}," +
|
||||
$"{Math.Round(point.Y / tolerance) * tolerance:F6}," +
|
||||
$"{Math.Round(point.Z / tolerance) * tolerance:F6}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算签名距离场(Signed Distance Field)
|
||||
/// </summary>
|
||||
/// <param name="mesh">DMesh3 网格</param>
|
||||
/// <param name="cellSize">网格单元尺寸(模型单位)</param>
|
||||
/// <returns>MeshSignedDistanceGrid 对象</returns>
|
||||
public static MeshSignedDistanceGrid ComputeSDF(DMesh3 mesh, double cellSize)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
LogManager.Info("=== 开始计算签名距离场 (SDF) ===");
|
||||
|
||||
MeshSignedDistanceGrid sdf = null;
|
||||
|
||||
try
|
||||
{
|
||||
// 获取网格边界
|
||||
var bounds = mesh.CachedBounds;
|
||||
LogManager.Info($"网格边界: {bounds.Min} ~ {bounds.Max}");
|
||||
LogManager.Info($"网格尺寸: {bounds.Width:F2} × {bounds.Height:F2} × {bounds.Depth:F2} 模型单位");
|
||||
|
||||
// 计算网格分辨率
|
||||
int nx = (int)Math.Ceiling(bounds.Width / cellSize);
|
||||
int ny = (int)Math.Ceiling(bounds.Height / cellSize);
|
||||
int nz = (int)Math.Ceiling(bounds.Depth / cellSize);
|
||||
|
||||
LogManager.Info($"SDF 网格分辨率: {nx} × {ny} × {nz} = {nx * ny * nz:N0} 个单元");
|
||||
LogManager.Info($"单元尺寸: {cellSize:F4} 模型单位");
|
||||
|
||||
// 创建 DMeshAABBTree3(空间索引树,加速距离查询)
|
||||
LogManager.Info("构建 AABB 树...");
|
||||
var spatialStopwatch = Stopwatch.StartNew();
|
||||
var spatial = new DMeshAABBTree3(mesh, autoBuild: true);
|
||||
spatialStopwatch.Stop();
|
||||
LogManager.Info($"AABB 树构建完成: {spatialStopwatch.ElapsedMilliseconds} ms");
|
||||
|
||||
// 计算 SDF
|
||||
LogManager.Info("开始计算距离场...");
|
||||
sdf = new MeshSignedDistanceGrid(mesh, cellSize, spatial);
|
||||
sdf.Compute();
|
||||
|
||||
stopwatch.Stop();
|
||||
LogManager.Info($"=== SDF 计算完成 ===");
|
||||
LogManager.Info($"计算耗时: {stopwatch.ElapsedMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds:F2} 秒)");
|
||||
|
||||
// 统计距离场信息
|
||||
AnalyzeSDF(sdf);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"计算 SDF 失败: {ex.Message}");
|
||||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||||
}
|
||||
|
||||
return sdf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分析 SDF 统计信息(简化版本)
|
||||
/// </summary>
|
||||
private static void AnalyzeSDF(MeshSignedDistanceGrid sdf)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dims = sdf.Dimensions;
|
||||
LogManager.Info($"SDF 维度: {dims.x} × {dims.y} × {dims.z}");
|
||||
LogManager.Info("SDF 创建成功,具体距离查询API需要进一步研究");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"分析 SDF 失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 完整测试流程:从 ModelItem 到 SDF
|
||||
/// </summary>
|
||||
/// <param name="modelItem">Navisworks 模型元素</param>
|
||||
/// <param name="cellSize">SDF 网格单元尺寸(模型单位)</param>
|
||||
/// <returns>MeshSignedDistanceGrid 对象</returns>
|
||||
public static MeshSignedDistanceGrid TestFullPipeline(ModelItem modelItem, double cellSize)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
LogManager.Info("=== 开始完整 SDF 测试流程 ===");
|
||||
LogManager.Info($"模型元素: {modelItem.DisplayName}");
|
||||
LogManager.Info($"SDF 单元尺寸: {cellSize:F4} 模型单位");
|
||||
|
||||
MeshSignedDistanceGrid sdf = null;
|
||||
|
||||
try
|
||||
{
|
||||
// 步骤 1:提取三角形
|
||||
LogManager.Info("[步骤 1/3] 提取三角形网格...");
|
||||
var triangles = GeometryHelper.ExtractTriangles(modelItem);
|
||||
|
||||
if (triangles.Count == 0)
|
||||
{
|
||||
LogManager.Error("未提取到三角形数据");
|
||||
return null;
|
||||
}
|
||||
|
||||
LogManager.Info($"提取到 {triangles.Count} 个三角形");
|
||||
|
||||
// 步骤 2:转换为 DMesh3
|
||||
LogManager.Info("[步骤 2/3] 转换到 DMesh3 格式...");
|
||||
var mesh = ConvertToDMesh3(triangles);
|
||||
|
||||
if (mesh.TriangleCount == 0)
|
||||
{
|
||||
LogManager.Error("DMesh3 网格为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
LogManager.Info($"DMesh3: {mesh.VertexCount} 顶点, {mesh.TriangleCount} 三角形");
|
||||
|
||||
// 步骤 3:计算 SDF
|
||||
LogManager.Info("[步骤 3/3] 计算签名距离场...");
|
||||
sdf = ComputeSDF(mesh, cellSize);
|
||||
|
||||
if (sdf == null)
|
||||
{
|
||||
LogManager.Error("SDF 计算失败");
|
||||
return null;
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
LogManager.Info($"=== 完整测试流程完成 ===");
|
||||
LogManager.Info($"总耗时: {stopwatch.ElapsedMilliseconds} ms ({stopwatch.Elapsed.TotalSeconds:F2} 秒)");
|
||||
|
||||
// 验证 SDF 正确性
|
||||
VerifySDFCorrectness(sdf, mesh);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"完整测试流程失败: {ex.Message}");
|
||||
LogManager.Error($"堆栈跟踪: {ex.StackTrace}");
|
||||
}
|
||||
|
||||
return sdf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证 SDF 正确性(简化版本)
|
||||
/// </summary>
|
||||
private static void VerifySDFCorrectness(MeshSignedDistanceGrid sdf, DMesh3 mesh)
|
||||
{
|
||||
LogManager.Info("=== 验证 SDF 正确性(简化版本) ===");
|
||||
|
||||
try
|
||||
{
|
||||
var bounds = mesh.CachedBounds;
|
||||
LogManager.Info($"网格边界: {bounds}");
|
||||
LogManager.Info("✅ SDF 创建成功,距离查询API需要进一步研究");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"SDF 验证失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建简单测试网格(手动构建立方体)
|
||||
/// </summary>
|
||||
/// <param name="size">立方体尺寸</param>
|
||||
/// <returns>DMesh3 立方体网格</returns>
|
||||
public static DMesh3 CreateTestCubeMesh(double size = 1.0)
|
||||
{
|
||||
LogManager.Info($"创建测试立方体网格: 尺寸={size}");
|
||||
|
||||
var mesh = new DMesh3(MeshComponents.None);
|
||||
|
||||
// 手动创建立方体的8个顶点
|
||||
double h = size / 2.0;
|
||||
int v0 = mesh.AppendVertex(new Vector3d(-h, -h, -h));
|
||||
int v1 = mesh.AppendVertex(new Vector3d(h, -h, -h));
|
||||
int v2 = mesh.AppendVertex(new Vector3d(h, h, -h));
|
||||
int v3 = mesh.AppendVertex(new Vector3d(-h, h, -h));
|
||||
int v4 = mesh.AppendVertex(new Vector3d(-h, -h, h));
|
||||
int v5 = mesh.AppendVertex(new Vector3d(h, -h, h));
|
||||
int v6 = mesh.AppendVertex(new Vector3d(h, h, h));
|
||||
int v7 = mesh.AppendVertex(new Vector3d(-h, h, h));
|
||||
|
||||
// 12个三角形(每个面2个三角形)
|
||||
mesh.AppendTriangle(v0, v2, v1); // 底面
|
||||
mesh.AppendTriangle(v0, v3, v2);
|
||||
mesh.AppendTriangle(v4, v5, v6); // 顶面
|
||||
mesh.AppendTriangle(v4, v6, v7);
|
||||
mesh.AppendTriangle(v0, v1, v5); // 前面
|
||||
mesh.AppendTriangle(v0, v5, v4);
|
||||
mesh.AppendTriangle(v2, v3, v7); // 后面
|
||||
mesh.AppendTriangle(v2, v7, v6);
|
||||
mesh.AppendTriangle(v0, v4, v7); // 左面
|
||||
mesh.AppendTriangle(v0, v7, v3);
|
||||
mesh.AppendTriangle(v1, v2, v6); // 右面
|
||||
mesh.AppendTriangle(v1, v6, v5);
|
||||
|
||||
LogManager.Info($"测试网格: {mesh.VertexCount} 顶点, {mesh.TriangleCount} 三角形");
|
||||
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user