Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IO/STL: speedup reading of ASCII files #93

Merged
merged 2 commits into from
Oct 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 37 additions & 59 deletions src/IO/STL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,19 +351,13 @@ int STLReader::inspectASCII(InspectionInfo *info)
m_fileHandle.seekg(0);

// Scan file
std::string line;
std::string word;
std::stringstream sline;
std::stringstream sname;

int inspectionError = 0;
while (getline(m_fileHandle, line)) {
line = utils::string::trim(line);
sline.clear(),
sline.str(line);

while (m_lineStream.readLine(m_fileHandle) >= 0) {
// Get keyword
if ((sline >> word) && (word.compare(ASCII_SOLID_BEGIN) == 0)) {
if ((m_lineStream >> word) && (word.compare(ASCII_SOLID_BEGIN) == 0)) {
// Initialize inspection info
int solidIndex = info->nSolids;

Expand All @@ -375,7 +369,7 @@ int STLReader::inspectASCII(InspectionInfo *info)

// Get solid name
sname.str("");
while (sline >> word) {
while (m_lineStream >> word) {
sname << word << " ";
}
std::string name = sname.str();
Expand Down Expand Up @@ -429,20 +423,15 @@ int STLReader::inspectSolidASCII(std::size_t *nFacets, std::array<bool, 6> *erro
}

// Inspect the solid
std::string line;
std::string word;
std::stringstream sline;
long last_valid_pos;

int inspectError = 0;
while (true) {
// Get next line
last_valid_pos = m_fileHandle.tellg();
getline(m_fileHandle, line);
line = utils::string::trim(line);
sline.clear();
sline.str(line);
if (!(sline >> word)) {
m_lineStream.readLine(m_fileHandle);
if (!(m_lineStream >> word)) {
word = "";
}

Expand Down Expand Up @@ -498,17 +487,12 @@ int STLReader::inspectFacetASCII(std::array<bool, 6> *errors)
}

// Check facet data
std::string line;
std::string word;
std::stringstream sline;
long last_valid_pos;

last_valid_pos = m_fileHandle.tellg();
getline(m_fileHandle, line);
line = utils::string::trim(line);
sline.clear(),
sline.str(line);
if ((!(sline >> word)) || (word.compare(ASCII_FACET_BEGIN) == 0)) {
m_lineStream.readLine(m_fileHandle);
if ((!(m_lineStream >> word)) || (word.compare(ASCII_FACET_BEGIN) == 0)) {
word = "begin";
}

Expand All @@ -522,11 +506,11 @@ int STLReader::inspectFacetASCII(std::array<bool, 6> *errors)

// Check facet normal or facet vertices
if (word.compare("begin") == 0) {
if ((sline >> word) && (word.compare("normal") == 0)) {
if ((m_lineStream >> word) && (word.compare("normal") == 0)) {
normal_found = true;

int nxyz = 0;
while (sline >> word) {
while (m_lineStream >> word) {
nxyz++;
}

Expand All @@ -539,7 +523,7 @@ int STLReader::inspectFacetASCII(std::array<bool, 6> *errors)
nV++;

int nxyz = 0;
while (sline >> word) {
while (m_lineStream >> word) {
nxyz++;
}

Expand All @@ -550,11 +534,8 @@ int STLReader::inspectFacetASCII(std::array<bool, 6> *errors)

// Get next line
last_valid_pos = m_fileHandle.tellg();
getline(m_fileHandle, line);
line = utils::string::trim(line);
sline.clear(),
sline.str(line);
if (!(sline >> word)) {
m_lineStream.readLine(m_fileHandle);
if (!(m_lineStream >> word)) {
word = "";
}
}
Expand Down Expand Up @@ -1005,9 +986,8 @@ int STLReader::readHeaderASCII(const std::string &solid, std::string *name, std:
utils::string::trim(solidKey);

// Scan file until solid is found
std::string line;
std::string word;
std::stringstream sline;
std::string line;

long start_pos = m_fileHandle.tellg();
long current_pos = start_pos + 1;
Expand All @@ -1016,10 +996,7 @@ int STLReader::readHeaderASCII(const std::string &solid, std::string *name, std:
bool wrapAround = solidKey.compare(ASCII_SOLID_BEGIN) != 0;
while (!solidFound && (start_pos != current_pos)) {
// Get current line
getline(m_fileHandle, line);
line = utils::string::trim(line);
sline.clear();
sline.str(line);
m_lineStream.readLine(m_fileHandle);

// Check end of file
if (m_fileHandle.eof()) {
Expand All @@ -1035,7 +1012,8 @@ int STLReader::readHeaderASCII(const std::string &solid, std::string *name, std:
current_pos = m_fileHandle.tellg();

// Look for keyword "solid"
if ((sline >> word) && (word.compare(ASCII_SOLID_BEGIN) == 0)) {
if ((m_lineStream >> word) && (word.compare(ASCII_SOLID_BEGIN) == 0)) {
m_lineStream.copyLine(&line);
if (solidKey.compare(ASCII_SOLID_BEGIN) == 0 || line.compare(solidKey) == 0) {
*name = line.erase(0, ASCII_SOLID_BEGIN.size());
*name = utils::string::trim(*name);
Expand Down Expand Up @@ -1090,24 +1068,21 @@ int STLReader::readFooterASCII(const std::string &solid)
utils::string::trim(solidKey);

// Look for the end of solid section
std::string line;
std::string word;
std::stringstream sline;
std::string line;

while (true) {
// Get next line
getline(m_fileHandle, line);
m_lineStream.readLine(m_fileHandle);

// Get next word
line = utils::string::trim(line);
sline.clear();
sline.str(line);
if (!(sline >> word)) {
if (!(m_lineStream >> word)) {
word = "";
}

// Handle the word
if (word.compare(ASCII_SOLID_END) == 0) {
m_lineStream.copyLine(&line);
if (line.compare(solidKey) != 0) {
log::cout() << "WARNING: end-solid key does not match the solid name." << std::endl;
log::cout() << " Expected end-solid key : " << solidKey << std::endl;
Expand Down Expand Up @@ -1144,9 +1119,8 @@ int STLReader::readFacetASCII(std::array<double, 3> *V0, std::array<double, 3> *
std::array<double, 3> *V2, std::array<double, 3> *N)
{
// Read facet data
std::string line;
std::string word;
std::stringstream sline;
std::string value;
long last_valid_pos;

int error = 0;
Expand All @@ -1155,13 +1129,8 @@ int STLReader::readFacetASCII(std::array<double, 3> *V0, std::array<double, 3> *
while (true) {
// Get next line
last_valid_pos = m_fileHandle.tellg();
getline(m_fileHandle, line);

// Get next word
line = utils::string::trim(line);
sline.clear();
sline.str(line);
if (!(sline >> word)) {
m_lineStream.readLine(m_fileHandle);
if (!(m_lineStream >> word)) {
continue;
}

Expand All @@ -1174,7 +1143,7 @@ int STLReader::readFacetASCII(std::array<double, 3> *V0, std::array<double, 3> *
if (word.compare(target) == 0) {
target = "normal";

if (!(sline >> word)) {
if (!(m_lineStream >> word)) {
continue;
}
} else {
Expand All @@ -1192,26 +1161,35 @@ int STLReader::readFacetASCII(std::array<double, 3> *V0, std::array<double, 3> *
}
} else if (word.compare("normal") == 0) {
if (word.compare(target) == 0) {
sline >> (*N);
for (int k = 0; k < 3; ++k) {
m_lineStream >> value;
(*N)[k] = stod(value);
}
target = "vertex";
} else {
error = -2;
break;
}
} else if (word.compare("vertex") == 0) {
if (word.compare(target) == 0) {
std::array<double, 3> *coords;
if (nFacetVertices == 0) {
sline >> *V0;
coords = V0;
} else if (nFacetVertices == 1) {
sline >> *V1;
coords = V1;
} else if (nFacetVertices == 2) {
sline >> *V2;
coords = V2;
target = ASCII_FACET_END;
} else {
error = -3;
break;
}

for (int k = 0; k < 3; ++k) {
m_lineStream >> value;
(*coords)[k] = stod(value);
}

nFacetVertices++;
} else {
error = -2;
Expand Down
4 changes: 4 additions & 0 deletions src/IO/STL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#include <fstream>
#include <iostream>

#include "line_stream.hpp"

namespace bitpit {

class STLBase {
Expand Down Expand Up @@ -126,6 +128,8 @@ class STLReader : public STLBase {
private:
std::ifstream m_fileHandle; /**< File handle */

LineStream m_lineStream; /**< Line stream */

int inspectASCII(InspectionInfo *info);
int inspectSolidASCII(std::size_t *nFactes, std::array<bool, 6> *errors);
int inspectFacetASCII(std::array<bool, 6> *errors);
Expand Down
112 changes: 112 additions & 0 deletions src/IO/line_stream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*---------------------------------------------------------------------------*\
*
* bitpit
*
* Copyright (C) 2015-2020 OPTIMAD engineering Srl
*
* -------------------------------------------------------------------------
* License
* This file is part of bitpit.
*
* bitpit is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License v3 (LGPL)
* as published by the Free Software Foundation.
*
* bitpit is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with bitpit. If not, see <http://www.gnu.org/licenses/>.
*
\*---------------------------------------------------------------------------*/

#include <cstring>

#include "line_stream.hpp"

namespace bitpit {

/*!
\class LineBuffer
\brief LineBuffer defines a buffer for reading lines.
*/

/*!
Constructor.
*/
LineBuffer::LineBuffer()
: m_buffer(CHUNK_SIZE)
{
}

/*!
Read a line from the file.

\param fileHandle is the file handle
*/
int LineBuffer::readLine(std::ifstream &fileHandle)
{
int lineLength = 0;
while (true) {
if (m_buffer.size() - lineLength < CHUNK_SIZE) {
m_buffer.resize(m_buffer.size() + CHUNK_SIZE);
}

fileHandle.getline(m_buffer.data() + lineLength, CHUNK_SIZE);
lineLength = strlen(m_buffer.data());

// If we haven't find the end of the line, we keep reading
if (fileHandle.good() || fileHandle.eof() || fileHandle.bad()) {
break;
} else if (fileHandle.fail()) {
fileHandle.clear();
}
}

setg(m_buffer.data(), m_buffer.data(), m_buffer.data() + lineLength);

if ((fileHandle.eof() || fileHandle.bad()) && lineLength == 0) {
return -1;
} else {
return lineLength;
}
}

/*!
Get a copy of the current line.

\param line on output will contain the current line
*/
void LineBuffer::copyLine(std::string *line) const
{
line->assign(eback(), egptr() - eback());
}

/*!
\class LineStream
\brief LineStream defines a stream for reading lines.
*/

/*!
Constructor.
*/
LineStream::LineStream()
: LineBuffer(), std::istream(this)
{
}

/*!
Read a line from the file.

\param fileHandle is the file handle
*/
int LineStream::readLine(std::ifstream &fileHandle)
{
std::istream::clear();

return static_cast<LineBuffer *>(std::istream::rdbuf())->readLine(fileHandle);
}

}
Loading