строка — Каков наиболее эффективный способ импорта файла .STL в C ++?

Какова наиболее эффективная стратегия анализа файла .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

Однако я заметил, что нет строгих требований к форматированию. И функция импорта должна выполнять минимальную проверку ошибок. Я сделал некоторые измерения производительности (используя хронограф), который для файла с 43 000 строк дает:

stl_import () — 1,177568 с

цикл разбора — 3.894250 с

Цикл разбора:

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?

-5

Решение

Без данных, которые могут быть использованы для измерения того, на что тратится время, сложно определить, что на самом деле повышает производительность. Приличная библиотека, уже выполняющая работу, может быть самым простым подходом. Тем не менее, текущий код использует несколько подходов, которые могут быть легко выиграть для повышения производительности. Есть вещи, которые я заметил:

  1. Библиотека потоков хороша для пропуска ведущих пробелов. Вместо первых пробелов с последующим их обрезанием вы можете использовать std::getline(infile >> std::ws, line): std::ws манипулятор пропускает ведущие пробелы.
  2. Вместо того, чтобы использовать starts_with() со строковыми литералами я предпочел бы прочитать каждую строку в «команду» и хвост строки и сравнить команды с std::string const объекты: вместо сравнения символов может быть достаточно сравнить размер.
  3. Вместо split()в std::string в std::vector<std::string> на пустом месте я бы предпочел сбросить подходящий поток (вероятно, std::istringstream но, чтобы предотвратить копирование, возможно, пользовательский поток памяти) и читать прямо из этого:

    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);
    }
    

    Этот подход имеет дополнительное преимущество, заключающееся в том, что он позволяет проверять формат: я всегда не доверяю полученным данным, даже если они получены из надежного источника.

  4. Если вы настаиваете на использовании корректировки последовательности символов и / или разбиения ее на подпоследовательности, я настоятельно рекомендую использовать std::string_view (или, в случае, если этот класс C ++ 17 недоступен аналогичного класса), чтобы избежать перемещения символов вокруг.
  5. Предполагая, что файл имеет значительный размер, я бы рекомендовал не читать файл в std::vector<std::string> а затем анализировать его. Вместо этого я бы проанализировал файл на лету: таким образом, горячая память немедленно используется повторно, а не перемещается из кэша для последующей постобработки. Таким образом можно избежать вспомогательного потока (см. Пункт 3 выше). Чтобы предотвратить слишком сложный цикл чтения, я бы разбил вложенные разделы на соответствующие функции, возвращая их по закрывающим тегам. Кроме того, я бы определил функции ввода для таких структур, как point просто читать их из потока.
  6. В зависимости от системы, в которой вы работаете, вы можете позвонить std::ios_base::sync_with_stdio(false) перед чтением файла: раньше была хотя бы одна часто используемая реализация потоков, которая выиграла бы от этого вызова.
2

Другие решения

Других решений пока нет …