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 ? "内部" : "外部")}");
//}
相关推荐
Surmon20 小时前
基于 Cloudflare 生态的 AI Agent 实现
前端·人工智能·架构
prince051 天前
用户积分系统怎么设计
java·大数据·数据库
六月June June1 天前
自定义调色盘组件
前端·javascript·调色盘
原来是猿1 天前
MySQL【内置函数】
数据库·mysql
難釋懷1 天前
Redis分片集群插槽原理
数据库·redis·缓存
SY_FC1 天前
实现一个父组件引入了子组件,跳转到其他页面,其他页面返回回来重新加载子组件函数
java·前端·javascript
糟糕好吃1 天前
我让 AI 操作网页之后,开始不想点按钮了
前端·javascript·后端
冷小鱼1 天前
pgvector 向量数据库完全指南:PostgreSQL 生态的 AI 增强
数据库·人工智能·postgresql
陈天伟教授1 天前
人工智能应用- 天文学家的助手:08. 星系定位与分类
前端·javascript·数据库·人工智能·机器学习
VaJoy1 天前
给到夯!前端工具链新标杆 Vite Plus 初探
前端·vite