在c++中导入.STL文件最有效的方法是什么?

问题描述 投票:0回答:2

解析 .STL 文件最有效的策略是什么?

我的代码的一个关键部分是导入 .STL 文件(一种常见的 CAD 文件格式),这限制了整体性能。

.STL 文件格式总结如下 - https://en.wikipedia.org/wiki/STL_(file_format)

此应用程序需要使用 ASCII 格式。

通用格式为:

solid name
    facet normal ni nj nk
        outer loop
            vertex v1x v1y v1z
            vertex v2x v2y v2z
            vertex v3x v3y v3z
        endloop
    endfacet
endsolid

但是,我注意到没有严格的格式要求。并且,导入函数必须执行最少量的错误检查。我已经做了一些性能测量(使用 chrono),对于 43,000 行的文件给出:

stl_import() - 1.177568 s

解析循环 - 3.894250 s

解析循环:

cout << "Importing " << stl_path << "... ";
    auto file_vec = import_stl(stl_path);
    for (auto& l : file_vec) {
        trim(l);
        if (solid_state) {
            if (facet_state) {
                if (starts_with(l, "vertex")) {

                    //---------ADD FACE----------//

                    l.erase(0, 6);
                    trim(l);

                    vector<string> strs;
                    split(strs, l, is_any_of(" "));

                    point p = { stod(strs[0]), stod(strs[1]), stod(strs[2]) };
                    facet_points.push_back(p);

                    //---------------------------//
                }
                else {
                    if (starts_with(l, "endfacet")) {
                        facet_state = false;
                    }
                }
            }
            else {
                if (starts_with(l, "facet")) {
                    facet_state = true;
                    //assert(facet_points.size() == 0);

                    //---------------------------//
                    //   Normals can be ignored  //
                    //---------------------------//

                }
                if (starts_with(l, "endsolid")) {
                    solid_state = false;
                }
            }
        }
        else {
            if (starts_with(l, "solid")) {
                solid_state = true;
            }
        }

        if (facet_points.size() == 3) {
            triangle facet(facet_points[0], facet_points[1], facet_points[2]);
            stl_solid.add_facet(facet);
            facet_points.clear();

            //check normal
            facet.normal();
        }
    }

stl_import函数是:

std::vector<std::string> import_stl(const std::string& file_path)
{
    std::ifstream infile(file_path);
    SkipBOM(infile);
    std::vector<std::string> file_vec;
    std::string line;
    while (std::getline(infile, line))
    {
        file_vec.push_back(line);
    }
    return file_vec;
}

我搜索了优化文件读取的方法等。并且,我发现使用 mmap 可以提高文件读取速度。

在 C++ 中快速读取文本文件

这个问题是询问.STL 文件的最佳解析策略是什么?

c++ string file parsing cad
2个回答
4
投票

如果没有可用于衡量时间花在哪里的数据,就很难确定什么真正提高了性能。一个像样的图书馆已经在做这项工作可能是最简单的方法。然而,当前的代码使用了一些可能很容易提高性能的方法。我发现了一些事情:

  1. streams 库非常擅长跳过前导空格。您可能需要使用
    std::getline(infile >> std::ws, line)
    ,而不是首先读取空格,然后将其修剪掉:
    std::ws
    操纵器会跳过前导空格。
  2. 而不是使用
    starts_with()
    与字符串文字,我宁愿将每一行读入“命令”和行尾,并将命令与
    std::string const
    对象进行比较:而不是字符比较,它可能足以比较尺寸。
  3. 而不是在空白处将

    split()
    放入
    std::string
    中,我宁愿重置一个合适的流(可能是
    std::vector<std::string>
    ,但为了防止复制可能的自定义内存流)并直接从中读取:
    
    
    std::istringstream

    这种方法的另一个优点是允许格式检查:我总是不信任收到的任何输入,即使它来自受信任的来源。

    如果您坚持使用调整字符序列和/或将其拆分为子序列,我强烈建议使用
  4. std::istringstream in; // declared outside the reading loop // ... point p; in.clear(); // get rid of potentially existing errors in.str(line); if (in >> p.x >> p.y >> p.z) { facet_points.push_back(p); }
  5. (或者,如果此 C++17 类不可用,则使用类似的类)以避免移动字符周围。
    假设文件很大,我建议不要将文件读入 
  6. std::string_view
  7. 然后解析它。相反,我会动态解析文件:这样热内存就会立即重用,而不是将其移出缓存以供以后进行后处理。这种方式可以避免处理辅助流(参见上面的第 3 点)。为了防止过于复杂的读取循环,我将嵌套部分拆分为适当的函数,并在结束标记上从它们返回。此外,我还为
    std::vector<std::string>
    等结构定义输入函数,以便简单地从流中读取它们。
    根据您正在使用的系统,您可能需要在读取文件之前调用 
  8. point
  9. :曾经至少有一种经常使用的流实现可以从该调用中受益。
    
        

0
投票
OpenSTL

,这是一个简单的仅头文件库。 std::ios_base::sync_with_stdio(false)

© www.soinside.com 2019 - 2024. All rights reserved.