geometry4Sharp Ray-Mesh求交 判断点是否在几何体内部

C# 7.3

geometry4Sharp 1.0.0

该C#代码实现了一个STL模型点位置检测器,使用geometry3Sharp库处理3D网格数据。核心功能包括:

  1. 加载STL文件并验证模型封闭性;

  2. 采用改进的射线投射算法(包含5次随机方向测试)判断点是否在模型内部;

  3. 提供单点和批量检测功能。

算法先进行快速边界框排除,再通过计算射线与三角形交点数确定位置,增强了结果的可靠性。适用于需要判断三维空间中点与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 ? "内部" : "外部")}");
//}
相关推荐
飞天狗1117 小时前
零基础JavaWeb入门——第2课:让网页“活”起来 —— JSP是什么?
java·开发语言·前端·后端·web
回忆2012初秋8 小时前
【Nginx】优雅地走进高性能 Web 服务器世界(1)
服务器·前端·nginx
信创工程师-小杨8 小时前
Linux内网环境如何解决依赖的问题
linux·运维·服务器
kyriewen8 小时前
Claude Code Token 烧太快?实测 5 招,把月费从 250 美金砍到 50 美金
前端·ai编程·claude
不吃土豆的马铃薯8 小时前
C++ 高性能网络缓冲区 Buffer 源码解析
linux·服务器·开发语言·网络·c++
小小龙学IT8 小时前
Go 泛型深度解析:从设计哲学到工程实践
服务器·数据库·golang
weixin_394758039 小时前
CRMEB Pro 商品字段二开:为什么加一个字段会牵动 SKU、缓存和前端展示?
前端·缓存
天行健,君子而铎9 小时前
2026年通用行业数据分类分级产品排名——聚焦成本低、全链路覆盖与高性能计算的优质选型
大数据·数据库·人工智能