如何检查 3d 网格的凸度?

Posted

技术标签:

【中文标题】如何检查 3d 网格的凸度?【英文标题】:How to check for convexity of a 3d mesh? 【发布时间】:2014-03-05 14:53:07 【问题描述】:

有没有快速的方法来做到这一点?在线搜索显示函数或单个多边形的凸性。但我需要能够检查整个模型。一个物体可以有凸面,但整体上可以是凹面的。

【问题讨论】:

检查相邻面之间的角度就足够了吗?如果有两个相邻的多边形(可能是三角形),它们之间的角度大于 pi (180),则网格是凹的。 是的,我同意,但要小心,如果您的网格没有严格的缠绕规则,那么很难确定哪一边是哪一边。顺便说一句,thorus 在环的内侧有凹面......如果网格包含至少一对凹面,那么它就是凹面!!!因为速度足以检查所有相邻的法线彼此 只是为了澄清:您是否试图确定由网格定义的表面是否为凸面,或者您是否试图确定由网格(作为边界)界定的点集是否为凸面? 【参考方案1】:

下意识:如果您构建一棵多叶 BSP 树并最终将所有几何图形都放在一个节点上,则该对象是凸的。

获得相同解决方案的更聪明的方法:对于每个多边形,获取超平面。确保模型中的每个顶点都位于该超平面的后面。

等价:检查每对顶点之间的线段;如果它不与任何面相交,则该对象是凸面的。

我想您也可以通过 quickhull 或其他方式获得凸包,并将其与原始对象进行比较。或者,类似地,获取凸包并检查原始对象的每个顶点是否位于凸包的一个面上。

【讨论】:

谢谢,但是将对象与凸包进行比较是行不通的,因为拓扑会不同。 这取决于您如何比较:如果您按照拓扑进行比较,那么您可能会看到不同之处。如果您通过其他方式这样做,那么您将不会。 你是对的。我认为体积比较不准确。不知道我还能如何比较,但我需要一种快速的方法来做到这一点,不幸的是,内置的凸包生成器非常慢。 你给了我们一些非常好的想法,但如果我必须选择,我会投票给第二个:)。【参考方案2】:

对于每个面,计算支撑平面的方程并检查所有顶点* 在插入平面方程时是否产生相同的符号。

O(F.V)F 面和V 顶点需要时间。

*为安全起见,请忽略正在处理的面的顶点。

或者,计算 3D 凸包,及时O(V.Log(V))。如果在算法的任何阶段一个顶点被丢弃,那么这个多面体不是凸的。

【讨论】:

【参考方案3】:
bool IsConvex(std::vector<vec3> &points, std::vector<int> &triangles, float threshold = 0.001)

    for (unsigned long i = 0; i < triangles.size() / 3; i++)
    
        vec3 Atmp = points[triangles[i * 3 + 0]];
        vec3 Btmp = points[triangles[i * 3 + 1]];
        vec3 Ctmp = points[triangles[i * 3 + 2]];

        btVector3 A(Atmp.x, Atmp.y, Atmp.z);
        btVector3 B(Btmp.x, Btmp.y, Btmp.z);
        btVector3 C(Ctmp.x, Ctmp.y, Ctmp.z);
        B -= A;
        C -= A;

        btVector3 BCNorm = B.cross(C).normalized();

        float checkPoint = btVector3(points[0].x - A.x(), points[0].y - A.y(), points[0].z - A.z()).dot(BCNorm);

        for (unsigned long j = 0; j < points.size(); j++)
        
            float dist = btVector3(points[j].x - A.x(), points[j].y - A.y(), points[j].z - A.z()).dot(BCNorm);
        
            if((std::abs(checkPoint) > threshold) && (std::abs(dist) > threshold) && (checkPoint * dist < 0))
            
                return false;
            
        
    

    return true;

【讨论】:

感谢您的回答。如果您可以添加算法如何工作的详细信息,那就太好了。不鼓励仅使用代码的答案,因为它们可能有效或无效,但不清楚原因,如果它们包含错误则更难发现。【参考方案4】:

trimesh 是一个 Python 库,可以加载 3D 网格并评估网格是否为凸面。

import trimesh
mesh = trimesh.load('my_mesh_file')
print(mesh.is_convex)

代码为here。

它可以通过以下指令从命令行运行:

python -m pip install trimesh
python -c "import trimesh; mesh = trimesh.load('my_mesh_file'); print(mesh.is_convex)"

【讨论】:

【参考方案5】:

您可以通过首先将所有顶点添加到树结构来加速平面顶点测试,因此如果它们的边界不与平面相交,您可以拒绝整个叶子。 BSP 的想法实际上应该与测试所有三角形平面相同,因为没有 BSP 叶子能够细分凸对象的顶点集。

您可能希望在平面测试中包含一个 epsilon,因为手动创建的网格的浮点精度和建模精度都可能导致顶点略高于平面。

【讨论】:

以上是关于如何检查 3d 网格的凸度?的主要内容,如果未能解决你的问题,请参考以下文章

Haskell 长度和滤波器确定线的凸度或凹度

OpenCV - 如何消除凸轮扫描仪中的凸面缺陷?

如何在 X 轴上镜像 3D 网格

如何使用 pcl 将 3D 点云离散化为 xy 平面上的 2D 网格,而不是使用体素网格?

点云/网格模型的体积计算

abaqus里面如下图复杂的模型应该怎样划分网格啊?求高手指点。