改进我读取STL文件的代码(c ++)

时间:2015-06-23 12:06:49

标签: string file import stl directx

为了使用DirectX创建3D模拟,我必须以ASCII-STL格式导入大量数据集。问题是我的读者工作但表现很糟糕。我与Autodesk Inventor STL导入器进行了比较,差异很大(5秒对1.5分钟)。我非常感谢您改进我的代码的建议或想法。谢谢!

此外,STL格式的效率非常低。对于每个面,顶点单独列出。看起来像下面这样:

facet normal 0 0.999229 0.0392606

外循环

vertex -3173.54 1993.84 -23184.5

vertex -3099.94 1993.84 -23184.5

vertex -3099.94 2000 -23341.5

ENDLOOP

endfacet

结果是在处理文件期间顶点出现了几次。我试图检查双顶点,但它需要永远的大文件(迭代变得越来越长)。

到目前为止,这是我的代码:

    std::ifstream stlFile;
stlFile.open(mFilename);
if(!stlFile) // check if file can be found
{
    MessageBox(0, "STL file not found.", 0, 0);
    return false;
}

std::string ignore;
stlFile >> ignore >> ignore; //ignore header: solid t=x.xx
UINT index = 0;

int iIndex = 0;
int vIndex = 0;
WORD indexTmp = 0;

while(1)
{
    stlFile >> ignore >> ignore; // ignore "normal"
    if (ignore == "CUBE")
        break;

    float normal[3];

    stlFile >> normal[0] >> normal[1] >> normal[2]; // read and save the face normal
    stlFile >> ignore >> ignore; // ignore "outer loop"
    for(int i = 0; i <= 2; ++i) // read the three vertices of a face
    {
        VERTEX vertexTmp;
        vertexTmp.Normal.x = normal[0]; vertexTmp.Normal.y = normal[1]; vertexTmp.Normal.z = normal[2];
        stlFile >> ignore >> vertexTmp.Pos.x >> vertexTmp.Pos.y >> vertexTmp.Pos.z;// >> ignore >> ignore;  

        //if (!ContainsVertexIndex(vertexTmp, vertices, indexTmp)) // return vertex index of double 
        //{
            mVertices.push_back(vertexTmp); //save newly created vertex     

            indexTmp = vIndex; // create index reference to the new vertex
            vIndex++; // increment index
        //}
        mIndices.push_back(indexTmp);
        iIndex++; // increment index
    }
    stlFile >> ignore >> ignore; // endloop // endfacet
}

stlFile.close();

编辑:我将矢量更改为固定数组,但性能没有显着提高。任何其他建议。

1 个答案:

答案 0 :(得分:2)

我刚刚遇到了这个问题并对你的速度问题有了一些了解。

您不应该使用矢量来存储此类型的数据。由于您经常检查向量中是否存在顶点,因此浪费了大量时间迭代向量。

更简单的方法是创建顶点的散列图。这允许进行恒定时间查找(实际上并不需要)和插入,这是您的处理瓶颈所在。那么你的总运行时间就是O(n),其中n是处理过的三角形数。

您需要能够对VERTEX对象进行哈希处理,这可以通过创建哈希模板来完成。我发现使用Boost的散列库最容易做到这一点,但你可以编写自己的散列库。

namespace std
{
     template<>
     struct hash<your_namespace::VERTEX>
     {
          typedef your_namespace::VERTEX argument_type;
          typedef size_t result_type;

          result_type operator()(const argument_type &v) const
          {
               result_type seed = 0;

               boost::hash_combine(seed, v.X);
               boost::hash_combine(seed, v.Y);
               boost::hash_combine(seed, v.Z);

               return seed;
          }
     }
}

Boost的hash_combine方法根据您对变量进行散列的顺序创建唯一的散列。因此,X-> Y-> Z产生与Z-> Y-> X不同的散列(因此每个序列组合产生唯一的输出)。

最后,使用地图数据结构来存储VERTEX数据对象。

// declaration
std::map<std::size_t, VERTEX> hashmap;

// adding VERTEX object
hashmap[std::hash<VERTEX>()(vObject)] = vObject;

使用此方法,您不必担心插入每个坐标集中的多个坐标集,因为散列坐标集会推断删除重复项。因此,不再通过循环遍历矢量数据结构来检查重复项。

希望这会有所帮助。我遇到了同样的瓶颈问题,这使我的STL读取时间从几分钟缩短到几毫秒。