c# - 计算三角形 3D 网格的质心

标签 c# math 3d mesh

我正在尝试计算 3D 三角形网格的质心。
编辑:事实证明我不是,我试图计算重心,这是不一样的
我的代码由点点滴滴组成,主要是:

  • This nice paper by Cha Zhang and Tsuhan Chen
  • SO : How to calculate the volume of a 3D mesh object the surface of which is made up triangles
  • SO : How to compute the centroid of a mesh with triangular faces?

  • 我将我的结果与 Rhino 提供的结果进行了比较。我计算质心和体积:
  • 引用 NURBS 体积与 Rhino 7
  • 使用 Rhino 7 的 27k 三角形网格
  • 使用 Rhino 7 的简化 1k 三角形网格
  • 与我的代码相同的 1k 三角形网格。

  • enter image description here
    如您所见,计算体积效果很好,但不适用于质心,我似乎不知道为什么。我需要误差小于 0.01。我检查了好几次,但肯定有一些明显的东西。
    我不太擅长数值不稳定:
  • 我应该以毫米而不是米为单位工作吗?
  • 我应该像galinette在第二个引用文献中所建议的那样,用另一个点而不是原点来计算四面体有符号体积吗?我试过了,并没有太大改善。

  • 我的代码
    在计算任何东西之前,我检查我的网格是否正确(未提供代码):
  • 封闭的网格,没有裸露的边缘或任何孔洞;
  • 所有三角形的顶点都是一致的,即三角形正确地朝向网格的外部。

  • using HelixToolkit.Wpf;
    using System.Collections.Generic;
    using System.Windows.Media.Media3D;
    
    internal static class CentroidHelper
    {
        public static Point3D Centroid(this List<MeshGeometry3D> meshes, out double volume)
        {
            Vector3D centroid = new Vector3D();
            volume = 0;
    
            foreach (var mesh in meshes)
            {
                var c = mesh.Centroid(out double v);
                volume += v;
                centroid += v *c ;
            }
    
            return (centroid / volume).ToPoint3D();
        }
    
        public static Vector3D Centroid(this MeshGeometry3D mesh, out double volume)
        {
            Vector3D centroid = new Vector3D();
            double totalArea = 0;
            volume = 0;
    
            for (int i = 0; i < mesh.TriangleIndices.Count; i += 3)
            {
                var a = mesh.Positions[mesh.TriangleIndices[i + 0]].ToVector3D();
                var b = mesh.Positions[mesh.TriangleIndices[i + 1]].ToVector3D();
                var c = mesh.Positions[mesh.TriangleIndices[i + 2]].ToVector3D();
                var triangleArea = AreaOfTriangle(a, b, c);
                totalArea += triangleArea;
                centroid += triangleArea * (a + b + c) / 3;
                    
                volume += SignedVolumeOfTetrahedron(a, b, c);
            }
            return centroid / totalArea;
        }
    
        private static double SignedVolumeOfTetrahedron(Vector3D a, Vector3D b, Vector3D c)
        {
            return Vector3D.DotProduct(a, Vector3D.CrossProduct(b, c)) / 6.0d;
        }
    
        private static double AreaOfTriangle(Vector3D a, Vector3D b, Vector3D c)
        {
            return 0.5d * Vector3D.CrossProduct(b - a, c - a).Length;
        }
    }    
    

    最佳答案

    原来是commonly accepted answer在堆栈溢出和整个互联网都是错误的:
    几何质心并不总是与质心重合,尽管它非常接近 .
    仅适用于某些卷,如 n-dimensional simplexesplatonic solids .
    我通过计算船舶平衡时的船体位置,将我的结果与 Rhino 的结果和现实进行了比较。
    想了很多,现在看来还是很明显的,但是非常欢迎大家来检查和批评我的方法。
    方法
    我使用了Zhang & Chen's paper中描述的方法的原理,质心。
    四面体的质心确实与其质心重合(即其顶点的等重心)。
    由四面体的有符号体积加权的质心的重心是网格的质心。
    Unit tetrahedron, from 3
    代码

    internal static class CentroidHelper
    {
        public static Point3D Centroid(this List<MeshGeometry3D> meshes, out double volume)
        {
            Vector3D centroid = new Vector3D();
            volume = 0;
    
            foreach (var mesh in meshes)
            {
                var c = mesh.Centroid(out double v);
                volume += v;
                centroid += v * c;
            }
            return (centroid / volume).ToPoint3D();
        }
    
        public static Vector3D Centroid(this MeshGeometry3D mesh, out double volume)
        {
            Vector3D centroid = new Vector3D();
            volume = 0;
    
            for (int i = 0; i < mesh.TriangleIndices.Count; i += 3)
            {
                var a = mesh.Positions[mesh.TriangleIndices[i + 0]].ToVector3D();
                var b = mesh.Positions[mesh.TriangleIndices[i + 1]].ToVector3D();
                var c = mesh.Positions[mesh.TriangleIndices[i + 2]].ToVector3D();
                var tetrahedronVolume = SignedVolumeOfTetrahedron(a, b, c);
                centroid += tetrahedronVolume * (a + b + c) / 4.0d;
                volume += tetrahedronVolume;
            }
            return centroid / volume;
        }
    
        private static double SignedVolumeOfTetrahedron(Vector3D a, Vector3D b, Vector3D c)
        {
            return Vector3D.DotProduct(a, Vector3D.CrossProduct(b, c)) / 6.0d;
        }
    }
    

    关于c# - 计算三角形 3D 网格的质心,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66891594/

    相关文章:

    c - 带阴影的快速 'ball' 像素光栅化例程

    android - 每天获取一组 "static"个随机值

    pdf - 如何从 ABAQUS/Viewer 打印 3D pdf?

    c# - 对二维数组的列求和

    c# - Stream.CopyTo 与 Librsync.PatchStream 一起使用时挂起

    java - 如何在java中找到给定输入的回归?

    generics - 通用数学运算符重载而不进行复制

    iphone - 如何旋转具有 3D 效果的图像?

    c# - 使用 MVVM 模式访问模型的最佳实践是什么

    c# - 监视系统中的进程启动