【问题标题】:A method to calculate the centre of mass from a .stl (stereo lithography) file?从.stl(立体光刻)文件计算质心的方法?
【发布时间】:2010-01-18 03:37:29
【问题描述】:

我正在尝试计算在 STL 文件中定义的对象的质心 (x,y,z) 坐标(立体光刻,不要与标准模板库混淆)。 STL 文件包含一个由三角形组成的边界定义的封闭对象(或多个对象)。三角形本身不一定按任何顺序,文件只是浮动在 3D 空间中的每个三角形的坐标 3 个顶点加上三角形的法线向量(法线应该被忽略,因为它并不总是正确完成)。没有任何东西可以将每个三角形相互联系起来,假设对象是闭合的。

一种简单的方法是将一个体积(在本例中为一个盒子)划分为数百万个元素,并确定每个元素是否在 STL 文件中定义的对象内,然后总结矩并计算中心质量。这会起作用,但它远非优雅且极其缓慢。

另一种方法是将边界表示转换为多个填充四面体实体。我可以计算每个四面体的质心、它的体积和产生的力矩的形式,从而从所有四面体的总和中计算出总质心。问题在于我不知道如何将三角形的表面表示转换为四面体的体积表示(我假设它是一项相当重要的任务)。

有没有人知道任何方法或想出我可以尝试的任何方法?或者甚至可能有任何关于这个的参考资料?

有关 STL 文件的更多信息(只有前 2 部分很重要,其他部分无用):http://en.wikipedia.org/wiki/STL_%28file_format%29

【问题讨论】:

    标签: c++ 3d theory


    【解决方案1】:

    经过大量思考和实验,我有了答案!

    首先,我们为每个三角形添加第 4 个点,使它们成为具有体积质心的四面体。我们计算质量的体积和中心,并将它们相乘以获得我们的时刻。我们将这些时刻相加并除以总体积以获得我们的整体质心。

    我们使用此处显示的确定方法(公式 32)计算体积:http://mathworld.wolfram.com/Tetrahedron.html

    每个四面体的质心只是 4 个点的平均值。

    这里的技巧是,由于创建 STL 文件的方式,三角形有一条从零件表面向外指向的法线,遵循用于创建三角形的 3 个顶点的右手定则。我们可以通过允许我们有一个一致的约定来利用这一点来确定是否应该从我们的净零件中添加或减去四面体的体积(这是因为我们选择的参考点可能不一定在零件内部并且整个部分不一定是凸的,而是一个封闭的物体。

    使用确定方法计算体积,前三个坐标点将代表我们三角形的三个点。第四点是我们共同的起源。如果三角形创建的法线(遵循从点 1、2、3 开始的右手法则)指向我们的公共参考点,则该体积将被计算为不属于我们整体实体的一部分,或负体积(通过指向,我的意思是三角形法线创建的向量松散地指向与从我们的参考点到四面体质心的向量创建的法线平面相同的一侧)。如果矢量指向远离参考点,则它是正体积或在零件内部。如果是正常的,那么体积会变为零,因为三角形与参考点在同一平面内。

    我们不需要担心实际跟踪任何这些,就好像我们与我们的输入一致(因为三角形遵循右手定则,法线从零件向外),确定将为我们提供正确的符号。

    总之,代码如下(比解释还简单)。

    class data // 3 vertices of each triangle
    {
    public:
        float x1,y1,z1;
        float x2,y2,z2;
        float x3,y3,z3;
    };
    
    int main ()
    {
        int numTriangles; // pull in the STL file and determine number of triangles
        data * triangles = new triangles [numTriangles];
        // fill the triangles array with the data in the STL file
    
        double totalVolume = 0, currentVolume;
        double xCenter = 0, yCenter = 0, zCenter = 0;
    
        for (int i = 0; i < numTriangles; i++)
        {
            totalVolume += currentVolume = (triangles[i].x1*triangles[i].y2*triangles[i].z3 - triangles[i].x1*triangles[i].y3*triangles[i].z2 - triangles[i].x2*triangles[i].y1*triangles[i].z3 + triangles[i].x2*triangles[i].y3*triangles[i].z1 + triangles[i].x3*triangles[i].y1*triangles[i].z2 - triangles[i].x3*triangles[i].y2*triangles[i].z1) / 6;
            xCenter += ((triangles[i].x1 + triangles[i].x2 + triangles[i].x3) / 4) * currentVolume;
            yCenter += ((triangles[i].y1 + triangles[i].y2 + triangles[i].y3) / 4) * currentVolume;
            zCenter += ((triangles[i].z1 + triangles[i].z2 + triangles[i].z3) / 4) * currentVolume;
        }
    
        cout << endl << "Total Volume = " << totalVolume << endl;
        cout << endl << "X center = " << xCenter/totalVolume << endl;
        cout << endl << "Y center = " << yCenter/totalVolume << endl;
        cout << endl << "Z center = " << zCenter/totalVolume << endl;
    }
    

    计算 STL 文件的质心速度极快。

    【讨论】:

    • 我想你会想要非常仔细地测试这个......我很难看出这怎么可能是正确的。在我看来,您正在寻找(接近)表面的质心,而不是填充体积的时刻。考虑一下如果你用同一平面上的多个三角形细分一个三角形会发生什么(就像生成谢尔宾斯基三角形的迭代) - 每个较小三角形的行列式将类似于较大三角形的 sqrt,你的结果将是对此有偏见。
    • 我已经根据 CAD 程序 (SolidWorks) 的结果对此进行了非常仔细的测试,结果精确到千分之一毫米。这里的诀窍是算法的大部分都被简化了,因为我选择了原点 (0,0,0) 作为第 4 个顶点。这抵消了问题的大部分复杂性,因此你最终得到的东西看起来像是在处理一个表面(因为你只看到 3 个点,第 4 个点抵消了与它相关的所有内容,因为它是零)。跨度>
    • 非常感谢。这有效:我已经彻底测试过了。很容易将其推广到非三角形网格(以 (x1,y1,z1) 作为刻面中的第一个点,从 2 循环到刻面中的点数并以 (x2,y2,z2) 作为点数i-1 和 (x3,y3,z3) 作为点编号 i。
    【解决方案2】:

    编辑:查找“绕组数算法”或“交叉数算法” - 我在下面尝试描述的是 3-d 交叉数算法。

    我感觉这样的东西会起作用,但我现在没有能力测试它:

    从 STL 文件中的三角形迭代构建填充的 3-d 结构。首先选择一个点作为 3-d 结构的基础。然后,通过创建一个三角锥来开始您的结构,其底部由 STL 文件中的第一个三角形定义,并以您选择的点为顶点。迭代构建的卷的每个此类组件也将包含一个“交叉奇偶校验” - 将其初始化为 0。

    对于 STL 文件中的每个后续三角形,创建一个类似的金字塔,并查看它是否与您迄今为止构建的 3-d 结构相交。如果是,计算交点,分割现有结构和新金字塔,使两个组件不重叠。保持新多面体最外层部分的“相交奇偶校验”为 0,但在相交的所有内部部分进行切换——如果为 0,则设为 1,如果为 1,则设为 0。

    最后,您将获得由结构的所有相交奇偶校验为 0 的部分定义的闭合多面体。计算所有这些多面体的矩,并将它们平均在一起以获得您的质心。我认为复杂度类似于 O(n^2)。

    【讨论】:

    • 嗯,我不太明白。所以我在任何地方选择了一个点,并开始使用空间中的那个点将每个三角形转换为四面体? (呵呵……n!复杂性让我有点害怕……我可以在一个文件中包含多达 200 万个三角形)
    • 非常感谢,这有点帮助(还有很长的路要走,但它是一个开始!)
    • 我认为复杂性已经关闭...没有仔细考虑。已编辑。
    • 嗯,看了之后,绕组数可能不是最好的。它可以让我确定一个点是否在内部,但我已经可以使用 CN 算法更快地做到这一点(我显然已经在使用......不知道)。我想我可以使用多边形算法区域的 3D 扩展来做到这一点……也许吧。看起来我应该能够用这种其他方法在 O(n) 中得到它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-17
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 2013-08-09
    • 1970-01-01
    • 2015-06-04
    相关资源
    最近更新 更多