From b799b5d65de3f8963cc58ab8c31e6aadb750f5f4 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Sun, 13 Nov 2016 23:04:38 +0100 Subject: [PATCH] ENH: surfMesh support for reading compressed binary stl files (issue #294) - increases coverage. STYLE: relocate some core pieces into fileFormats --- src/fileFormats/Make/files | 3 + .../stl/STLCore.C} | 277 ++++++++---------- src/fileFormats/stl/STLCore.H | 115 ++++++++ src/fileFormats/stl/STLReader.C | 188 ++++++++++++ .../stl/STLReader.H} | 63 ++-- .../stl/STLReaderASCII.L} | 34 ++- .../stl/STLpoint.H | 11 +- .../stl/STLtriangle.H | 32 +- .../stl/STLtriangleI.H | 61 +++- src/surfMesh/Make/files | 2 - .../surfaceFormats/stl/STLsurfaceFormat.C | 70 +++-- .../surfaceFormats/stl/STLsurfaceFormat.H | 26 +- 12 files changed, 639 insertions(+), 243 deletions(-) rename src/{surfMesh/surfaceFormats/stl/STLsurfaceFormatCore.C => fileFormats/stl/STLCore.C} (51%) create mode 100644 src/fileFormats/stl/STLCore.H create mode 100644 src/fileFormats/stl/STLReader.C rename src/{surfMesh/surfaceFormats/stl/STLsurfaceFormatCore.H => fileFormats/stl/STLReader.H} (78%) rename src/{surfMesh/surfaceFormats/stl/STLsurfaceFormatASCII.L => fileFormats/stl/STLReaderASCII.L} (93%) rename src/{surfMesh/surfaceFormats => fileFormats}/stl/STLpoint.H (91%) rename src/{surfMesh/surfaceFormats => fileFormats}/stl/STLtriangle.H (80%) rename src/{surfMesh/surfaceFormats => fileFormats}/stl/STLtriangleI.H (61%) diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files index 8919e3392d..87fd35ee22 100644 --- a/src/fileFormats/Make/files +++ b/src/fileFormats/Make/files @@ -10,6 +10,9 @@ ensight/type/ensightPTraits.C nas/NASCore.C fire/FIRECore.C starcd/STARCDCore.C +stl/STLCore.C +stl/STLReader.C +stl/STLReaderASCII.L vtk/foamVtkCore.C vtk/format/foamVtkAppendBase64Formatter.C diff --git a/src/surfMesh/surfaceFormats/stl/STLsurfaceFormatCore.C b/src/fileFormats/stl/STLCore.C similarity index 51% rename from src/surfMesh/surfaceFormats/stl/STLsurfaceFormatCore.C rename to src/fileFormats/stl/STLCore.C index 022b6df5a9..a38d3a3cdf 100644 --- a/src/surfMesh/surfaceFormats/stl/STLsurfaceFormatCore.C +++ b/src/fileFormats/stl/STLCore.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | + \\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -23,36 +23,75 @@ License \*---------------------------------------------------------------------------*/ -#include "STLsurfaceFormatCore.H" +#include "STLCore.H" #include "gzstream.h" #include "OSspecific.H" -#include "Map.H" #include "IFstream.H" -#include "Ostream.H" -#undef DEBUG_STLBINARY +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +//! \cond fileScope -// check binary by getting the header and number of facets +// The number of bytes in the STL binary header +static const unsigned STLHeaderSize = 80; + +//! \endcond + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::fileFormats::STLCore::STLCore() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::fileFormats::STLCore::isBinaryName +( + const fileName& filename, + const STLFormat& format +) +{ + return (format == DETECT ? (filename.ext() == "stlb") : format == BINARY); +} + + +// Check binary by getting the header and number of facets // this seems to work better than the old token-based method // - some programs (eg, pro-STAR) have 'solid' as the first word in // the binary header. // - using wordToken can cause an abort if non-word (binary) content // is detected ... this is not exactly what we want. -int Foam::fileFormats::STLsurfaceFormatCore::detectBINARY +int Foam::fileFormats::STLCore::detectBinaryHeader ( const fileName& filename ) { - off_t dataFileSize = Foam::fileSize(filename); + bool compressed = false; + autoPtr streamPtr + ( + new ifstream(filename.c_str(), std::ios::binary) + ); - IFstream str(filename, IOstream::BINARY); - istream& is = str().stdStream(); + // If the file is compressed, decompress it before further checking. + if (!streamPtr->good() && isFile(filename + ".gz", false)) + { + compressed = true; + streamPtr.reset(new igzstream((filename + ".gz").c_str())); + } + istream& is = streamPtr(); + + if (!is.good()) + { + FatalErrorInFunction + << "Cannot read file " << filename + << " or file " << filename + ".gz" + << exit(FatalError); + } // Read the STL header - char header[headerSize]; - is.read(header, headerSize); + char header[STLHeaderSize]; + is.read(header, STLHeaderSize); // Check that stream is OK, if not this may be an ASCII file if (!is.good()) @@ -60,7 +99,7 @@ int Foam::fileFormats::STLsurfaceFormatCore::detectBINARY return 0; } - // Read the number of triangles in the STl file + // Read the number of triangles in the STL file // (note: read as int so we can check whether >2^31) int nTris; is.read(reinterpret_cast(&nTris), sizeof(unsigned int)); @@ -74,33 +113,73 @@ int Foam::fileFormats::STLsurfaceFormatCore::detectBINARY ( !is || nTris < 0 - || nTris < (dataFileSize - headerSize)/50 - || nTris > (dataFileSize - headerSize)/25 ) { return 0; } + else if (!compressed) + { + const off_t dataFileSize = Foam::fileSize(filename); + + if + ( + nTris < int(dataFileSize - STLHeaderSize)/50 + || nTris > int(dataFileSize - STLHeaderSize)/25 + ) + { + return 0; + } + } // looks like it might be BINARY, return number of triangles return nTris; } -bool Foam::fileFormats::STLsurfaceFormatCore::readBINARY +Foam::autoPtr +Foam::fileFormats::STLCore::readBinaryHeader ( - istream& is, - const off_t dataFileSize + const fileName& filename, + label& nTrisEstimated ) { - sorted_ = true; + bool bad = false; + bool compressed = false; + nTrisEstimated = 0; + + autoPtr streamPtr + ( + new ifstream(filename.c_str(), std::ios::binary) + ); + + // If the file is compressed, decompress it before reading. + if (!streamPtr->good() && isFile(filename + ".gz", false)) + { + compressed = true; + streamPtr.reset(new igzstream((filename + ".gz").c_str())); + } + istream& is = streamPtr(); + + if (!is.good()) + { + streamPtr.clear(); + + FatalErrorInFunction + << "Cannot read file " << filename + << " or file " << filename + ".gz" + << exit(FatalError); + } + // Read the STL header - char header[headerSize]; - is.read(header, headerSize); + char header[STLHeaderSize]; + is.read(header, STLHeaderSize); // Check that stream is OK, if not this may be an ASCII file if (!is.good()) { + streamPtr.clear(); + FatalErrorInFunction << "problem reading header, perhaps file is not binary " << exit(FatalError); @@ -116,156 +195,56 @@ bool Foam::fileFormats::STLsurfaceFormatCore::readBINARY // // Also compare the file size with that expected from the number of tris // If the comparison is not sensible then it may be an ASCII file - if - ( - !is - || nTris < 0 - || nTris < int(dataFileSize - headerSize)/50 - || nTris > int(dataFileSize - headerSize)/25 - ) + if (!is || nTris < 0) { + bad = true; + } + else if (!compressed) + { + const off_t dataFileSize = Foam::fileSize(filename); + + if + ( + nTris < int(dataFileSize - STLHeaderSize)/50 + || nTris > int(dataFileSize - STLHeaderSize)/25 + ) + { + bad = true; + } + } + + if (bad) + { + streamPtr.clear(); + FatalErrorInFunction << "problem reading number of triangles, perhaps file is not binary" << exit(FatalError); } -#ifdef DEBUG_STLBINARY - Info<< "# " << nTris << " facets" << endl; - label prevZone = -1; -#endif - - points_.setSize(3*nTris); - zoneIds_.setSize(nTris); - - Map