C# 7.3
geometry4Sharp 1.0.0
该C#代码实现了一个STL模型点位置检测器,使用geometry3Sharp库处理3D网格数据。核心功能包括:
-
加载STL文件并验证模型封闭性;
-
采用改进的射线投射算法(包含5次随机方向测试)判断点是否在模型内部;
-
提供单点和批量检测功能。
算法先进行快速边界框排除,再通过计算射线与三角形交点数确定位置,增强了结果的可靠性。适用于需要判断三维空间中点与STL模型位置关系的应用场景。
cs
using g4;
using System;
using System.Collections.Generic;
public class STLPointChecker
{
private DMesh3 mesh;
private AxisAlignedBox3d bounds;
public STLPointChecker(string stlFilePath)
{
DMesh3Builder builder = new DMesh3Builder();
StandardMeshReader reader = new StandardMeshReader() { MeshBuilder = builder };
IOReadResult result = reader.Read(stlFilePath, ReadOptions.Defaults);
if (result.code == IOCode.Ok)
mesh = builder.Meshes[0];
if (mesh == null)
return;
if (!mesh.IsClosed())
throw new Exception("STL模型不是封闭的,无法判断内外");
bounds = mesh.CachedBounds;
}
// 射线法判断点是否在内部(基础可靠版)
public bool IsPointInside(Vector3d testPoint)
{
if (mesh == null)
{
Console.WriteLine("Mesh is null");
return false;
}
// 快速边界框排除
if (!bounds.Contains(testPoint))
return false;
// 创建射线(沿X轴正方向)
Ray3d ray = new Ray3d(testPoint, Vector3d.AxisX);
int intersectionCount = 0;
var rand = new Random();
// 为确保稳定性,可发射多条随机方向的射线取多数结果
for (int i = 0; i < 5; i++)
{
if (i > 0) // 第一次用X轴,后续用随机方向
{
Vector3d randomDir = new Vector3d(
rand.NextDouble() * 2.0 - 1.0,
rand.NextDouble() * 2.0 - 1.0,
rand.NextDouble() * 2.0 - 1.0
).Normalized;
ray = new Ray3d(testPoint, randomDir);
}
int count = CountRayIntersections(ray);
if (count % 2 == 1) // 奇数个交点在内部
intersectionCount++;
}
// 5条射线中3条以上认为在内部则判定为内部
return intersectionCount >= 3;
}
private int CountRayIntersections(Ray3d ray)
{
int count = 0;
// 遍历所有三角形
foreach (int tid in mesh.TriangleIndices())
{
// 使用 geometry3Sharp 内置的高效求交方法
IntrRay3Triangle3 intersection = new IntrRay3Triangle3(ray,
new Triangle3d(
mesh.GetVertex(mesh.GetTriangle(tid).a),
mesh.GetVertex(mesh.GetTriangle(tid).b),
mesh.GetVertex(mesh.GetTriangle(tid).c)
)
);
if (intersection.Find() && intersection.IsSimpleIntersection)
{
if (intersection.RayParameter > 0) // 确保交点在射线正方向
count++;
}
}
return count;
}
// 批量检查多个点
public Dictionary<Vector3d, bool> CheckPoints(List<Vector3d> points)
{
var results = new Dictionary<Vector3d, bool>();
foreach (var point in points)
{
results[point] = IsPointInside(point);
}
return results;
}
}
// 使用示例
//var checker = new STLPointChecker(@"E:\Data\PathPlanning\convex_hull.stl");
//// 检查单个点
//Vector3d testPoint = new Vector3d(10.0, 5.0, 2.0);
//bool inside = checker.IsPointInside(testPoint);
//Console.WriteLine($"点 ({testPoint.x}, {testPoint.y}, {testPoint.z}) 在内部: {inside}");
//// 批量检查
//var points = new List<Vector3d>
// {
// new Vector3d(0, 0, 0),
// new Vector3d(50, 50, 50),
// new Vector3d(-10, -10, -10),
// new Vector3d(2104.38, 633.567, 775.12)
// };
//var results = checker.CheckPoints(points);
//foreach (var kvp in results)
//{
// Console.WriteLine($"点 {kvp.Key}: {(kvp.Value ? "内部" : "外部")}");
//}