mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add alternative STL ASCII parsers
- In addition to the traditional Flex-based parser, added a Ragel-based
parser and a handwritten one.
Some representative timings for reading 5874387 points (1958129 tris):
Flex Ragel Manual
5.2s 4.8s 6.7s total reading time
3.8s 3.4s 5.3s without point merging
This commit is contained in:
@ -191,7 +191,12 @@ int main(int argc, char *argv[])
|
|||||||
Info<<"camel-case => " << (word("camel") & "case") << nl;
|
Info<<"camel-case => " << (word("camel") & "case") << nl;
|
||||||
for (const auto& s : { " text with \"spaces'", "08/15 value" })
|
for (const auto& s : { " text with \"spaces'", "08/15 value" })
|
||||||
{
|
{
|
||||||
Info<<"validated \"" << s << "\" => "
|
// Character sequence
|
||||||
|
|
||||||
|
Info<<"validated 5 chars from \" => "
|
||||||
|
<< word::validate(s, s+5, true) << nl;
|
||||||
|
|
||||||
|
Info<<"validated (via string convert) \"" << s << "\" => "
|
||||||
<< word::validate(s, true) << nl;
|
<< word::validate(s, true) << nl;
|
||||||
}
|
}
|
||||||
Info<< nl;
|
Info<< nl;
|
||||||
|
|||||||
3
applications/test/surfaceReading/Make/files
Normal file
3
applications/test/surfaceReading/Make/files
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Test-surfaceReading.C
|
||||||
|
|
||||||
|
EXE = $(FOAM_APPBIN)/Test-surfaceReading
|
||||||
6
applications/test/surfaceReading/Make/options
Normal file
6
applications/test/surfaceReading/Make/options
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
EXE_INC = \
|
||||||
|
-I$(LIB_SRC)/fileFormats/lnInclude \
|
||||||
|
-I$(LIB_SRC)/surfMesh/lnInclude
|
||||||
|
|
||||||
|
EXE_LIBS = \
|
||||||
|
-lsurfMesh
|
||||||
145
applications/test/surfaceReading/Test-surfaceReading.C
Normal file
145
applications/test/surfaceReading/Test-surfaceReading.C
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM 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 General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Application
|
||||||
|
Test-surfaceReading
|
||||||
|
|
||||||
|
Description
|
||||||
|
Test basic surface format reading capabilities (and speeds)
|
||||||
|
|
||||||
|
Note
|
||||||
|
The filename extensions are used to determine the file format type.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "argList.H"
|
||||||
|
#include "Time.H"
|
||||||
|
#include "clockTime.H"
|
||||||
|
#include "triSurface.H"
|
||||||
|
#include "MeshedSurfaces.H"
|
||||||
|
#include "UnsortedMeshedSurfaces.H"
|
||||||
|
#include "STLReader.H"
|
||||||
|
|
||||||
|
using namespace Foam;
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
argList::addNote
|
||||||
|
(
|
||||||
|
"Test basic surface format reading capabilities (and speeds)"
|
||||||
|
);
|
||||||
|
|
||||||
|
argList::noParallel();
|
||||||
|
argList::addArgument("inputFile");
|
||||||
|
|
||||||
|
argList::addBoolOption
|
||||||
|
(
|
||||||
|
"triSurface",
|
||||||
|
"Use triSurface for read"
|
||||||
|
);
|
||||||
|
argList::addBoolOption
|
||||||
|
(
|
||||||
|
"triFace",
|
||||||
|
"Use triFace instead of face"
|
||||||
|
);
|
||||||
|
argList::addBoolOption
|
||||||
|
(
|
||||||
|
"unsorted",
|
||||||
|
"Use UnsortedMeshedSurface instead of MeshedSurface, "
|
||||||
|
"or unsorted output (with -triSurface option)"
|
||||||
|
);
|
||||||
|
|
||||||
|
argList::addOption
|
||||||
|
(
|
||||||
|
"ext",
|
||||||
|
"name",
|
||||||
|
"Force alternative extension"
|
||||||
|
);
|
||||||
|
|
||||||
|
argList::addOption
|
||||||
|
(
|
||||||
|
"stl-parser",
|
||||||
|
"N",
|
||||||
|
"ASCII parser type: 0=Flex, 1=Ragel, 2=Manual"
|
||||||
|
);
|
||||||
|
|
||||||
|
#include "setRootCase.H"
|
||||||
|
|
||||||
|
const fileName importName = args[1];
|
||||||
|
|
||||||
|
word ext;
|
||||||
|
if (!args.readIfPresent("ext", ext))
|
||||||
|
{
|
||||||
|
ext = importName.ext();
|
||||||
|
if (ext == "gz")
|
||||||
|
{
|
||||||
|
ext = importName.lessExt().ext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.readIfPresent("stl-parser", fileFormats::STLReader::parserType);
|
||||||
|
|
||||||
|
clockTime timing;
|
||||||
|
|
||||||
|
if (args.found("triSurface"))
|
||||||
|
{
|
||||||
|
triSurface surf(importName, ext);
|
||||||
|
|
||||||
|
Info<< "Read surface:" << endl;
|
||||||
|
surf.writeStats(Info);
|
||||||
|
Info<< "Area : " << sum(surf.magSf()) << nl << endl;
|
||||||
|
}
|
||||||
|
else if (args.found("triFace"))
|
||||||
|
{
|
||||||
|
MeshedSurface<triFace> surf(importName, ext);
|
||||||
|
|
||||||
|
Info<< "Read surface:" << endl;
|
||||||
|
surf.writeStats(Info);
|
||||||
|
Info<< "Area : " << sum(surf.magSf()) << nl << endl;
|
||||||
|
}
|
||||||
|
else if (args.found("unsorted"))
|
||||||
|
{
|
||||||
|
UnsortedMeshedSurface<face> surf(importName, ext);
|
||||||
|
|
||||||
|
Info<< "Read surface:" << endl;
|
||||||
|
surf.writeStats(Info);
|
||||||
|
Info<< "Area : " << sum(surf.magSf()) << nl << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MeshedSurface<face> surf(importName, ext);
|
||||||
|
|
||||||
|
Info<< "Read surface:" << endl;
|
||||||
|
surf.writeStats(Info);
|
||||||
|
Info<< "Area : " << sum(surf.magSf()) << nl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< nl << "Reading took " << timing.elapsedTime() << "s" << nl
|
||||||
|
<< "\nEnd\n" << endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -121,8 +121,12 @@ OptimisationSwitches
|
|||||||
|
|
||||||
// Force dumping (at next timestep) upon signal (-1 to disable) and exit
|
// Force dumping (at next timestep) upon signal (-1 to disable) and exit
|
||||||
stopAtWriteNowSignal -1;
|
stopAtWriteNowSignal -1;
|
||||||
|
|
||||||
|
//- Choose STL ASCII parser: 0=Flex, 1=Ragel, 2=Manual
|
||||||
|
fileFormats::stl 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Can specify fallback profiling settings
|
/* Can specify fallback profiling settings
|
||||||
profiling
|
profiling
|
||||||
{
|
{
|
||||||
|
|||||||
@ -50,7 +50,7 @@ Foam::fileName Foam::fileName::validate
|
|||||||
out.resize(s.size());
|
out.resize(s.size());
|
||||||
|
|
||||||
char prev = 0;
|
char prev = 0;
|
||||||
std::string::size_type count = 0;
|
std::string::size_type len = 0;
|
||||||
|
|
||||||
// Largely as per stripInvalid
|
// Largely as per stripInvalid
|
||||||
for (auto iter = s.cbegin(); iter != s.cend(); ++iter)
|
for (auto iter = s.cbegin(); iter != s.cend(); ++iter)
|
||||||
@ -66,17 +66,17 @@ Foam::fileName Foam::fileName::validate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only track valid chars
|
// Only track valid chars
|
||||||
out[count++] = prev = c;
|
out[len++] = prev = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doClean && prev == '/' && count > 1)
|
if (doClean && prev == '/' && len > 1)
|
||||||
{
|
{
|
||||||
// Avoid trailing '/'
|
// Avoid trailing '/'
|
||||||
--count;
|
--len;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.resize(count);
|
out.resize(len);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -222,17 +222,18 @@ inline String Foam::string::validate(const std::string& str)
|
|||||||
String out;
|
String out;
|
||||||
out.resize(str.size());
|
out.resize(str.size());
|
||||||
|
|
||||||
size_type count = 0;
|
size_type len = 0;
|
||||||
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
|
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
|
||||||
{
|
{
|
||||||
const char c = *iter;
|
const char c = *iter;
|
||||||
if (String::valid(c))
|
if (String::valid(c))
|
||||||
{
|
{
|
||||||
out[count++] = c;
|
out[len] = c;
|
||||||
|
++len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.resize(count);
|
out.resize(len);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,7 @@ Foam::word Foam::word::validate(const std::string& s, const bool prefix)
|
|||||||
word out;
|
word out;
|
||||||
out.resize(s.size() + (prefix ? 1 : 0));
|
out.resize(s.size() + (prefix ? 1 : 0));
|
||||||
|
|
||||||
std::string::size_type count = 0;
|
std::string::size_type len = 0;
|
||||||
|
|
||||||
// As per validate, but optionally detect if the first character
|
// As per validate, but optionally detect if the first character
|
||||||
// is a digit, which we'd like to avoid having since this will
|
// is a digit, which we'd like to avoid having since this will
|
||||||
@ -52,17 +52,51 @@ Foam::word Foam::word::validate(const std::string& s, const bool prefix)
|
|||||||
|
|
||||||
if (word::valid(c))
|
if (word::valid(c))
|
||||||
{
|
{
|
||||||
if (!count && prefix && isdigit(c))
|
if (!len && prefix && isdigit(c))
|
||||||
{
|
{
|
||||||
// First valid character was a digit - prefix with '_'
|
// First valid character was a digit - prefix with '_'
|
||||||
out[count++] = '_';
|
out[len++] = '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
out[count++] = c;
|
out[len++] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.resize(count);
|
out.resize(len);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::word Foam::word::validate
|
||||||
|
(
|
||||||
|
const char* first,
|
||||||
|
const char* last,
|
||||||
|
const bool prefix
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::string::size_type len = (last - first) + (prefix ? 1 : 0);
|
||||||
|
|
||||||
|
word out;
|
||||||
|
out.resize(len);
|
||||||
|
|
||||||
|
for (len=0; first != last; ++first)
|
||||||
|
{
|
||||||
|
const char c = *first;
|
||||||
|
|
||||||
|
if (word::valid(c))
|
||||||
|
{
|
||||||
|
if (!len && prefix && isdigit(c))
|
||||||
|
{
|
||||||
|
// First valid character was a digit - prefix with '_'
|
||||||
|
out[len++] = '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
out[len++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.resize(len);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,6 +148,16 @@ public:
|
|||||||
// that work nicely as dictionary keywords.
|
// that work nicely as dictionary keywords.
|
||||||
static word validate(const std::string& s, const bool prefix=false);
|
static word validate(const std::string& s, const bool prefix=false);
|
||||||
|
|
||||||
|
//- Construct validated word (no invalid characters) from a sequence
|
||||||
|
//- of characters in the range [first,last),
|
||||||
|
// Optionally prefix any leading digit with '_'.
|
||||||
|
static word validate
|
||||||
|
(
|
||||||
|
const char* first,
|
||||||
|
const char* last,
|
||||||
|
const bool prefix=false
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// File-like Functions
|
// File-like Functions
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,9 @@ fire/FIRECore.C
|
|||||||
starcd/STARCDCore.C
|
starcd/STARCDCore.C
|
||||||
stl/STLCore.C
|
stl/STLCore.C
|
||||||
stl/STLReader.C
|
stl/STLReader.C
|
||||||
stl/STLReaderASCII.L
|
stl/STLAsciiParseFlex.L
|
||||||
|
stl/STLAsciiParseManual.C
|
||||||
|
stl/STLAsciiParseRagel.C
|
||||||
|
|
||||||
vtk/core/foamVtkCore.C
|
vtk/core/foamVtkCore.C
|
||||||
vtk/core/foamVtkPTraits.C
|
vtk/core/foamVtkPTraits.C
|
||||||
|
|||||||
153
src/fileFormats/stl/STLAsciiParse.H
Normal file
153
src/fileFormats/stl/STLAsciiParse.H
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM 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 General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::Detail::STLAsciiParse
|
||||||
|
|
||||||
|
Description
|
||||||
|
Internal class used when parsing STL ASCII format
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
STLAsciiParse.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef STLAsciiParse_H
|
||||||
|
#define STLAsciiParse_H
|
||||||
|
|
||||||
|
#include "DynamicList.H"
|
||||||
|
#include "HashTable.H"
|
||||||
|
#include "STLpoint.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace Detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class Detail::STLAsciiParse Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class STLAsciiParse
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Protected Data
|
||||||
|
|
||||||
|
bool sorted_;
|
||||||
|
label groupId_; // The current solid group
|
||||||
|
label lineNum_;
|
||||||
|
|
||||||
|
//- The number of local points on the current facet
|
||||||
|
int nFacetPoints_;
|
||||||
|
|
||||||
|
//- Current vertex component when reading 'vertex'
|
||||||
|
int nVertexCmpt_;
|
||||||
|
|
||||||
|
//- Scratch space for reading 'vertex'
|
||||||
|
STLpoint currVertex_;
|
||||||
|
|
||||||
|
DynamicList<STLpoint> points_;
|
||||||
|
DynamicList<label> facets_;
|
||||||
|
DynamicList<word> names_;
|
||||||
|
DynamicList<label> sizes_;
|
||||||
|
HashTable<label> nameLookup_;
|
||||||
|
|
||||||
|
|
||||||
|
// Protected Member Functions
|
||||||
|
|
||||||
|
//- Action when entering 'solid'
|
||||||
|
inline void beginSolid(word solidName);
|
||||||
|
|
||||||
|
//- Action when entering 'facet'
|
||||||
|
inline void beginFacet();
|
||||||
|
|
||||||
|
//- Reset vertex component to zero
|
||||||
|
inline void resetVertex();
|
||||||
|
|
||||||
|
//- Add next vertex component. On each third call, adds the point.
|
||||||
|
// \return true when point has been added (on the last component)
|
||||||
|
inline bool addVertexComponent(float val);
|
||||||
|
|
||||||
|
//- Add next vertex component. On each third call, adds the point.
|
||||||
|
// \return true when point has been added (on the last component)
|
||||||
|
inline bool addVertexComponent(const char* text);
|
||||||
|
|
||||||
|
//- Action on 'endfacet'
|
||||||
|
inline void endFacet();
|
||||||
|
|
||||||
|
|
||||||
|
//- No copy construct
|
||||||
|
STLAsciiParse(const STLAsciiParse&) = delete;
|
||||||
|
|
||||||
|
//- No copy assignment
|
||||||
|
void operator=(const STLAsciiParse&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- From input stream and the approximate number of vertices in the STL
|
||||||
|
inline STLAsciiParse(const label approxNpoints);
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Reset stored values
|
||||||
|
inline void clear();
|
||||||
|
|
||||||
|
//- Do all the solid groups appear in order?
|
||||||
|
inline bool sorted() const;
|
||||||
|
|
||||||
|
//- A list of unstitched triangle points
|
||||||
|
inline DynamicList<STLpoint>& points();
|
||||||
|
|
||||||
|
//- A list of facet IDs (group IDs)
|
||||||
|
//- corresponds to the number of triangles
|
||||||
|
inline DynamicList<label>& facets();
|
||||||
|
|
||||||
|
//- Solid names in the order of their appearance.
|
||||||
|
inline DynamicList<word>& names();
|
||||||
|
|
||||||
|
//- Solid sizes in the order of their appearance.
|
||||||
|
inline DynamicList<label>& sizes();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace Detail
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#include "STLAsciiParseI.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
|
\\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -21,18 +21,21 @@ License
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Description
|
||||||
|
Flex-based parsing of STL ASCII format
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
%option prefix="yySTL"
|
%option prefix="yySTL"
|
||||||
%option yyclass="yySTLFlexLexer"
|
%option yyclass="yySTLFlexLexer"
|
||||||
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ *\
|
/* ------------------------------------------------------------------------ *\
|
||||||
------ local definitions
|
------ local definitions
|
||||||
\* ------------------------------------------------------------------------ */
|
\* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#include "STLAsciiParse.H"
|
||||||
#include "STLReader.H"
|
#include "STLReader.H"
|
||||||
#include "OSspecific.H"
|
#include "OSspecific.H"
|
||||||
|
|
||||||
@ -40,6 +43,7 @@ License
|
|||||||
#pragma clang diagnostic ignored "-Wdeprecated-register"
|
#pragma clang diagnostic ignored "-Wdeprecated-register"
|
||||||
|
|
||||||
using namespace Foam;
|
using namespace Foam;
|
||||||
|
|
||||||
// Dummy yyFlexLexer::yylex() to keep the linker happy. It is not called
|
// Dummy yyFlexLexer::yylex() to keep the linker happy. It is not called
|
||||||
//! \cond dummy
|
//! \cond dummy
|
||||||
#if YY_FLEX_MAJOR_VERSION <= 2 && YY_FLEX_MINOR_VERSION <= 5 && YY_FLEX_SUBMINOR_VERSION < 34
|
#if YY_FLEX_MAJOR_VERSION <= 2 && YY_FLEX_MINOR_VERSION <= 5 && YY_FLEX_SUBMINOR_VERSION < 34
|
||||||
@ -67,32 +71,27 @@ int yySTLFlexLexer::yywrap()
|
|||||||
}
|
}
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
|
|
||||||
//- A lexer for parsing STL ASCII files.
|
//- A lexer for parsing STL ASCII files.
|
||||||
// Returns DynamicList(s) of points and facets (zoneIds).
|
// Returns DynamicList(s) of points and facets (zoneIds).
|
||||||
// The facets are within a solid/endsolid grouping
|
// The facets are within a solid/endsolid grouping
|
||||||
class STLASCIILexer
|
class STLAsciiParseFlex
|
||||||
:
|
:
|
||||||
|
public Detail::STLAsciiParse,
|
||||||
public yySTLFlexLexer
|
public yySTLFlexLexer
|
||||||
{
|
{
|
||||||
// Private data
|
|
||||||
|
|
||||||
bool sorted_;
|
|
||||||
label groupID_; // current solid group
|
|
||||||
label lineNo_;
|
|
||||||
word startError_;
|
word startError_;
|
||||||
|
|
||||||
DynamicList<STLpoint> points_;
|
|
||||||
DynamicList<label> facets_;
|
|
||||||
DynamicList<word> names_;
|
|
||||||
DynamicList<label> sizes_;
|
|
||||||
HashTable<label> lookup_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- From input stream and the approximate number of vertices in the STL
|
//- From input stream and the approximate number of vertices in the STL
|
||||||
STLASCIILexer(istream* is, const label approxNpoints);
|
STLAsciiParseFlex(istream* is, const label approxNpoints)
|
||||||
|
:
|
||||||
|
Detail::STLAsciiParse(approxNpoints),
|
||||||
|
yySTLFlexLexer(is)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
// Member Functions
|
// Member Functions
|
||||||
@ -100,78 +99,39 @@ public:
|
|||||||
//- The lexer function itself
|
//- The lexer function itself
|
||||||
int lex();
|
int lex();
|
||||||
|
|
||||||
// Access
|
//- Execute lexer
|
||||||
|
void execute()
|
||||||
//- Do all the solid groups appear in order?
|
|
||||||
inline bool sorted() const
|
|
||||||
{
|
{
|
||||||
return sorted_;
|
while (lex()) {}
|
||||||
}
|
|
||||||
|
|
||||||
//- A list of unstitched triangle points
|
|
||||||
inline DynamicList<STLpoint>& points()
|
|
||||||
{
|
|
||||||
return points_;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- A list of facet IDs (group IDs)
|
|
||||||
// corresponds to the number of triangles
|
|
||||||
inline DynamicList<label>& facets()
|
|
||||||
{
|
|
||||||
return facets_;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Solid names in the order of their appearance.
|
|
||||||
inline DynamicList<word>& names()
|
|
||||||
{
|
|
||||||
return names_;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Solid sizes in the order of their appearance.
|
|
||||||
inline DynamicList<label>& sizes()
|
|
||||||
{
|
|
||||||
return sizes_;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
STLASCIILexer::STLASCIILexer(istream* is, const label approxNpoints)
|
|
||||||
:
|
|
||||||
yySTLFlexLexer(is),
|
|
||||||
sorted_(true),
|
|
||||||
groupID_(-1),
|
|
||||||
lineNo_(1),
|
|
||||||
points_(approxNpoints),
|
|
||||||
facets_(approxNpoints)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ *\
|
/* ------------------------------------------------------------------------ *\
|
||||||
------ cppLexer::yylex()
|
------ cppLexer::yylex()
|
||||||
\* ------------------------------------------------------------------------ */
|
\* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
#undef YY_DECL
|
#undef YY_DECL
|
||||||
#define YY_DECL int STLASCIILexer::lex()
|
#define YY_DECL int STLAsciiParseFlex::lex()
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
one_space [ \t\f\r]
|
white [ \t\f\r]
|
||||||
space {one_space}*
|
space {white}*
|
||||||
some_space {one_space}+
|
some_space {white}+
|
||||||
|
|
||||||
alpha [_A-Za-z]
|
alpha [_A-Za-z]
|
||||||
digit [0-9]
|
digit [0-9]
|
||||||
|
|
||||||
integer {digit}+
|
intNum [-+]?{digit}+
|
||||||
signedInteger [-+]?{integer}
|
|
||||||
|
|
||||||
word ([[:alnum:]]|[[:punct:]])*
|
word ([[:alnum:]]|[[:punct:]])*
|
||||||
string {word}({some_space}{word})*
|
string {word}({some_space}{word})*
|
||||||
|
|
||||||
exponent_part [eE][-+]?{digit}+
|
expon [Ee][-+]?{digit}+
|
||||||
fractional_constant [-+]?(({digit}*"."{digit}+)|({digit}+"."?))
|
fract [-+]?(({digit}*"."{digit}+)|({digit}+"."?))
|
||||||
|
|
||||||
floatNum (({fractional_constant}{exponent_part}?)|({digit}+{exponent_part}))
|
floatNum (({fract}{expon}?)|({digit}+{expon}))
|
||||||
|
|
||||||
x {floatNum}
|
x {floatNum}
|
||||||
y {floatNum}
|
y {floatNum}
|
||||||
@ -205,13 +165,6 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
%%
|
%%
|
||||||
|
|
||||||
%{
|
%{
|
||||||
// End of read character pointer returned by strtof
|
|
||||||
// char* endPtr;
|
|
||||||
|
|
||||||
label cmpt = 0; // Component index when reading vertex
|
|
||||||
STLpoint vertex;
|
|
||||||
// STLpoint normal;
|
|
||||||
|
|
||||||
static const char* stateNames[7] =
|
static const char* stateNames[7] =
|
||||||
{
|
{
|
||||||
"reading solid",
|
"reading solid",
|
||||||
@ -247,62 +200,13 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
}
|
}
|
||||||
|
|
||||||
<readSolidName>{string} {
|
<readSolidName>{string} {
|
||||||
const word solidName(word::validate(YYText()));
|
beginSolid(word::validate(YYText()));
|
||||||
|
|
||||||
auto iter = lookup_.cfind(solidName);
|
|
||||||
if (iter.found())
|
|
||||||
{
|
|
||||||
if (groupID_ != iter.object())
|
|
||||||
{
|
|
||||||
sorted_ = false; // Group appeared out of order
|
|
||||||
groupID_ = iter.object();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
groupID_ = sizes_.size();
|
|
||||||
if (lookup_.insert(solidName, groupID_))
|
|
||||||
{
|
|
||||||
names_.append(solidName);
|
|
||||||
sizes_.append(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FatalErrorInFunction<< "Duplicate solid-name: " << solidName
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
<readSolidName>{space}\n {
|
<readSolidName>{space}\n {
|
||||||
const word solidName("solid"); // Could also use solid0, solid1, ...
|
beginSolid("solid"); // Could also use solid0, solid1, ...
|
||||||
|
++lineNum_;
|
||||||
auto iter = lookup_.cfind(solidName);
|
|
||||||
if (iter.found())
|
|
||||||
{
|
|
||||||
if (groupID_ != iter.object())
|
|
||||||
{
|
|
||||||
sorted_ = false; // Group appeared out of order
|
|
||||||
groupID_ = iter.object();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
groupID_ = sizes_.size();
|
|
||||||
if (lookup_.insert(solidName, groupID_))
|
|
||||||
{
|
|
||||||
names_.append(solidName);
|
|
||||||
sizes_.append(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FatalErrorInFunction<< "Duplicate solid-name: " << solidName
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++lineNo_;
|
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,6 +215,7 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
}
|
}
|
||||||
|
|
||||||
{facet} {
|
{facet} {
|
||||||
|
beginFacet();
|
||||||
BEGIN(readFacet);
|
BEGIN(readFacet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,24 +242,16 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
BEGIN(readVertex);
|
BEGIN(readVertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
<readVertex>{space}{signedInteger}{space} {
|
<readVertex>{space}{intNum}{space} {
|
||||||
vertex[cmpt++] = atol(YYText());
|
if (addVertexComponent(float(::atol(YYText()))))
|
||||||
|
|
||||||
if (cmpt == 3)
|
|
||||||
{
|
{
|
||||||
cmpt = 0;
|
|
||||||
points_.append(vertex);
|
|
||||||
BEGIN(readVertices);
|
BEGIN(readVertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<readVertex>{space}{floatNum}{space} {
|
<readVertex>{space}{floatNum}{space} {
|
||||||
vertex[cmpt++] = atof(YYText());
|
if (addVertexComponent(::atof(YYText())))
|
||||||
|
|
||||||
if (cmpt == 3)
|
|
||||||
{
|
{
|
||||||
cmpt = 0;
|
|
||||||
points_.append(vertex);
|
|
||||||
BEGIN(readVertices);
|
BEGIN(readVertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,8 +261,7 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
}
|
}
|
||||||
|
|
||||||
<readFacet>{endfacet} {
|
<readFacet>{endfacet} {
|
||||||
facets_.append(groupID_);
|
endFacet();
|
||||||
sizes_[groupID_]++;
|
|
||||||
BEGIN(INITIAL);
|
BEGIN(INITIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +272,7 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
/* ---------------- Ignore remaining spaces and newlines ------------------ */
|
/* ---------------- Ignore remaining spaces and newlines ------------------ */
|
||||||
|
|
||||||
<*>{space} {}
|
<*>{space} {}
|
||||||
<*>\n { ++lineNo_; }
|
<*>\n { ++lineNum_; }
|
||||||
|
|
||||||
|
|
||||||
/* ------------------- Any other characters are errors -------------------- */
|
/* ------------------- Any other characters are errors -------------------- */
|
||||||
@ -392,7 +288,7 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
<stlError>.* {
|
<stlError>.* {
|
||||||
yy_pop_state();
|
yy_pop_state();
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< "while " << stateNames[YY_START] << " on line " << lineNo_ << nl
|
<< "while " << stateNames[YY_START] << " on line " << lineNum_ << nl
|
||||||
<< " expected " << stateExpects[YY_START]
|
<< " expected " << stateExpects[YY_START]
|
||||||
<< " but found '" << startError_.c_str() << YYText() << "'"
|
<< " but found '" << startError_.c_str() << YYText() << "'"
|
||||||
<< exit(FatalError);
|
<< exit(FatalError);
|
||||||
@ -408,15 +304,13 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// member function
|
// Member Function
|
||||||
//
|
//
|
||||||
bool Foam::fileFormats::STLReader::readASCII
|
bool Foam::fileFormats::STLReader::readAsciiFlex
|
||||||
(
|
(
|
||||||
const fileName& filename
|
const fileName& filename
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
format_ = STLFormat::UNKNOWN;
|
|
||||||
|
|
||||||
IFstream is(filename);
|
IFstream is(filename);
|
||||||
if (!is)
|
if (!is)
|
||||||
{
|
{
|
||||||
@ -425,20 +319,12 @@ bool Foam::fileFormats::STLReader::readASCII
|
|||||||
<< exit(FatalError);
|
<< exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the lexer with the approximate number of vertices in the STL
|
// Create with approx number of vertices in the STL (from file size)
|
||||||
// from the file size
|
STLAsciiParseFlex lexer(&(is.stdStream()), Foam::fileSize(filename)/400);
|
||||||
STLASCIILexer lexer(&(is.stdStream()), Foam::fileSize(filename)/400);
|
lexer.execute();
|
||||||
while (lexer.lex() != 0) {}
|
|
||||||
|
|
||||||
sorted_ = lexer.sorted();
|
transfer(lexer);
|
||||||
|
|
||||||
// Transfer to normal lists
|
|
||||||
points_.transfer(lexer.points());
|
|
||||||
zoneIds_.transfer(lexer.facets());
|
|
||||||
names_.transfer(lexer.names());
|
|
||||||
sizes_.transfer(lexer.sizes());
|
|
||||||
|
|
||||||
format_ = STLFormat::ASCII;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
192
src/fileFormats/stl/STLAsciiParseI.H
Normal file
192
src/fileFormats/stl/STLAsciiParseI.H
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM 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 General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
inline void Foam::Detail::STLAsciiParse::beginSolid(word solidName)
|
||||||
|
{
|
||||||
|
if (solidName.empty())
|
||||||
|
{
|
||||||
|
solidName = "solid"; // Could also use solid0, solid1, ...
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iter = nameLookup_.cfind(solidName);
|
||||||
|
if (iter.found())
|
||||||
|
{
|
||||||
|
if (groupId_ != iter.object())
|
||||||
|
{
|
||||||
|
sorted_ = false; // Group appeared out of order
|
||||||
|
groupId_ = iter.object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
groupId_ = sizes_.size();
|
||||||
|
if (nameLookup_.insert(solidName, groupId_))
|
||||||
|
{
|
||||||
|
names_.append(solidName);
|
||||||
|
sizes_.append(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorInFunction<< "Duplicate solid-name: " << solidName
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Foam::Detail::STLAsciiParse::beginFacet()
|
||||||
|
{
|
||||||
|
nFacetPoints_ = 0;
|
||||||
|
nVertexCmpt_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Foam::Detail::STLAsciiParse::resetVertex()
|
||||||
|
{
|
||||||
|
nVertexCmpt_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Foam::Detail::STLAsciiParse::addVertexComponent(float val)
|
||||||
|
{
|
||||||
|
currVertex_[nVertexCmpt_] = val;
|
||||||
|
|
||||||
|
if (++nVertexCmpt_ == 3)
|
||||||
|
{
|
||||||
|
points_.append(currVertex_);
|
||||||
|
nVertexCmpt_ = 0;
|
||||||
|
++nFacetPoints_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !nVertexCmpt_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Foam::Detail::STLAsciiParse::addVertexComponent(const char* text)
|
||||||
|
{
|
||||||
|
//-> safer, but slower: readFloat(text, currVertex_[nVertexCmpt_]);
|
||||||
|
currVertex_[nVertexCmpt_] = ::atof(text);
|
||||||
|
|
||||||
|
if (++nVertexCmpt_ == 3)
|
||||||
|
{
|
||||||
|
points_.append(currVertex_);
|
||||||
|
nVertexCmpt_ = 0;
|
||||||
|
++nFacetPoints_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !nVertexCmpt_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Foam::Detail::STLAsciiParse::endFacet()
|
||||||
|
{
|
||||||
|
if (nFacetPoints_ == 3)
|
||||||
|
{
|
||||||
|
facets_.append(groupId_);
|
||||||
|
sizes_[groupId_]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nFacetPoints_ > 3)
|
||||||
|
{
|
||||||
|
nFacetPoints_ -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nFacetPoints_)
|
||||||
|
{
|
||||||
|
points_.resize(points_.size() - nFacetPoints_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nFacetPoints_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
inline Foam::Detail::STLAsciiParse::STLAsciiParse(const label approxNpoints)
|
||||||
|
:
|
||||||
|
sorted_(true),
|
||||||
|
groupId_(-1),
|
||||||
|
lineNum_(1),
|
||||||
|
nFacetPoints_(0),
|
||||||
|
nVertexCmpt_(0),
|
||||||
|
points_(approxNpoints),
|
||||||
|
facets_(approxNpoints/2)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
inline void Foam::Detail::STLAsciiParse::clear()
|
||||||
|
{
|
||||||
|
sorted_ = true;
|
||||||
|
groupId_ = -1;
|
||||||
|
lineNum_ = 0;
|
||||||
|
|
||||||
|
nFacetPoints_ = 0;
|
||||||
|
nVertexCmpt_ = 0;
|
||||||
|
|
||||||
|
points_.clear();
|
||||||
|
facets_.clear();
|
||||||
|
names_.clear();
|
||||||
|
sizes_.clear();
|
||||||
|
nameLookup_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Foam::Detail::STLAsciiParse::sorted() const
|
||||||
|
{
|
||||||
|
return sorted_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Foam::DynamicList<Foam::STLpoint>& Foam::Detail::STLAsciiParse::points()
|
||||||
|
{
|
||||||
|
return points_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Foam::DynamicList<Foam::label>& Foam::Detail::STLAsciiParse::facets()
|
||||||
|
{
|
||||||
|
return facets_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Foam::DynamicList<Foam::word>& Foam::Detail::STLAsciiParse::names()
|
||||||
|
{
|
||||||
|
return names_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Foam::DynamicList<Foam::label>& Foam::Detail::STLAsciiParse::sizes()
|
||||||
|
{
|
||||||
|
return sizes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
423
src/fileFormats/stl/STLAsciiParseManual.C
Normal file
423
src/fileFormats/stl/STLAsciiParseManual.C
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM 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 General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Description
|
||||||
|
Hand-written parsing of STL ASCII format
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "STLAsciiParse.H"
|
||||||
|
#include "STLReader.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
#include "stringOps.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
static inline std::string perrorEOF(std::string expected)
|
||||||
|
{
|
||||||
|
return "Premature EOF while reading '" + expected + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline std::string perrorParse(std::string expected, std::string found)
|
||||||
|
{
|
||||||
|
return "Parse error. Expecting '" + expected + "' found '" + found + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace Detail
|
||||||
|
{
|
||||||
|
|
||||||
|
//- A lexer for parsing STL ASCII files.
|
||||||
|
// Returns DynamicList(s) of points and facets (zoneIds).
|
||||||
|
// The facets are within a solid/endsolid grouping
|
||||||
|
class STLAsciiParseManual
|
||||||
|
:
|
||||||
|
public Detail::STLAsciiParse
|
||||||
|
{
|
||||||
|
enum scanState
|
||||||
|
{
|
||||||
|
scanSolid = 0,
|
||||||
|
scanFacet,
|
||||||
|
scanLoop,
|
||||||
|
scanVerts,
|
||||||
|
scanEndLoop,
|
||||||
|
scanEndFacet,
|
||||||
|
scanEndSolid
|
||||||
|
};
|
||||||
|
|
||||||
|
scanState state_;
|
||||||
|
|
||||||
|
std::string errMsg_;
|
||||||
|
|
||||||
|
//- Like std:csub_match
|
||||||
|
typedef std::pair<const char*, const char*> tokenType;
|
||||||
|
|
||||||
|
// Tokenized line
|
||||||
|
DynamicList<tokenType, 16> tokens_;
|
||||||
|
|
||||||
|
//- Tokenize
|
||||||
|
inline std::string::size_type tokenize(const char *p, const char *pe)
|
||||||
|
{
|
||||||
|
const char* start = p;
|
||||||
|
tokens_.clear();
|
||||||
|
|
||||||
|
// Find not space
|
||||||
|
while (p < pe && isspace(*p))
|
||||||
|
{
|
||||||
|
if (*p == '\n' && lineNum_)
|
||||||
|
{
|
||||||
|
++lineNum_;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p != pe)
|
||||||
|
{
|
||||||
|
const char* beg = p;
|
||||||
|
|
||||||
|
// Find space
|
||||||
|
while (p < pe && !isspace(*p))
|
||||||
|
{
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
tokens_.append(tokenType(beg, p));
|
||||||
|
|
||||||
|
// Find next
|
||||||
|
while (p < pe && isspace(*p))
|
||||||
|
{
|
||||||
|
if (*p == '\n')
|
||||||
|
{
|
||||||
|
++lineNum_;
|
||||||
|
return (p - start);
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (p - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- From input stream and the approximate number of vertices in the STL
|
||||||
|
STLAsciiParseManual(const label approxNpoints)
|
||||||
|
:
|
||||||
|
Detail::STLAsciiParse(approxNpoints)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//- Execute parser
|
||||||
|
void execute(std::istream& is);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Detail
|
||||||
|
} // end of namespace Foam
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
// Length of the input read buffer
|
||||||
|
#define INBUFLEN 16384
|
||||||
|
|
||||||
|
void Foam::Detail::STLAsciiParseManual::execute(std::istream& is)
|
||||||
|
{
|
||||||
|
if (!is)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffering
|
||||||
|
char inbuf[INBUFLEN];
|
||||||
|
std::streamsize pending = 0;
|
||||||
|
|
||||||
|
lineNum_ = 0;
|
||||||
|
|
||||||
|
state_ = scanSolid;
|
||||||
|
errMsg_.clear();
|
||||||
|
|
||||||
|
// Line-oriented processing loop
|
||||||
|
while (is)
|
||||||
|
{
|
||||||
|
if (pending >= INBUFLEN)
|
||||||
|
{
|
||||||
|
// We overfilled the buffer while trying to scan a token...
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "buffer full while scanning near line " << lineNum_ << nl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *data = inbuf + pending; // current data buffer
|
||||||
|
const std::streamsize buflen = INBUFLEN - pending; // space in buffer
|
||||||
|
|
||||||
|
is.read(data, buflen);
|
||||||
|
const std::streamsize gcount = is.gcount();
|
||||||
|
|
||||||
|
if (!gcount)
|
||||||
|
{
|
||||||
|
// EOF
|
||||||
|
// If scanning for next "solid" this is a valid way to exit, but
|
||||||
|
// an error if scanning for the initial "solid" or any other token
|
||||||
|
|
||||||
|
switch (state_)
|
||||||
|
{
|
||||||
|
case scanSolid:
|
||||||
|
{
|
||||||
|
if (!lineNum_) errMsg_ = perrorEOF("solid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case scanFacet: { errMsg_ = perrorEOF("facet"); break; }
|
||||||
|
case scanLoop: { errMsg_ = perrorEOF("outer loop"); break; }
|
||||||
|
case scanVerts: { errMsg_ = perrorEOF("vertex"); break; }
|
||||||
|
case scanEndLoop: { errMsg_ = perrorEOF("endloop"); break; }
|
||||||
|
case scanEndFacet: { errMsg_ = perrorEOF("endfacet"); break; }
|
||||||
|
case scanEndSolid: { errMsg_ = perrorEOF("endsolid"); break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate the parsing loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// p,pe = Ragel parsing point and parsing end (default naming)
|
||||||
|
// eof = Ragel EOF point (default naming)
|
||||||
|
|
||||||
|
char *p = inbuf;
|
||||||
|
char *pe = data + gcount;
|
||||||
|
|
||||||
|
// Line-oriented: search backwards to find last newline
|
||||||
|
{
|
||||||
|
--pe;
|
||||||
|
while (*pe != '\n' && pe >= inbuf)
|
||||||
|
{
|
||||||
|
--pe;
|
||||||
|
}
|
||||||
|
++pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cmd;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Tokenize
|
||||||
|
const auto parsedLen = tokenize(p, pe);
|
||||||
|
p += parsedLen;
|
||||||
|
if (!parsedLen || tokens_.empty())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure consistent case on the first token
|
||||||
|
cmd.assign(tokens_[0].first, tokens_[0].second);
|
||||||
|
stringOps::lower(cmd);
|
||||||
|
|
||||||
|
// Handle all expected parse states
|
||||||
|
switch (state_)
|
||||||
|
{
|
||||||
|
case scanSolid:
|
||||||
|
{
|
||||||
|
if (cmd == "solid")
|
||||||
|
{
|
||||||
|
if (tokens_.empty())
|
||||||
|
{
|
||||||
|
beginSolid(word::null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
beginSolid
|
||||||
|
(
|
||||||
|
word::validate(tokens_[1].first, tokens_[1].second)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
state_ = scanFacet; // Next state
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = perrorParse("solid", cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case scanFacet:
|
||||||
|
{
|
||||||
|
if (cmd == "color")
|
||||||
|
{
|
||||||
|
// Optional 'color' entry (after solid)
|
||||||
|
// - continue looking for 'facet'
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (cmd == "facet")
|
||||||
|
{
|
||||||
|
beginFacet();
|
||||||
|
state_ = scanLoop; // Next state
|
||||||
|
}
|
||||||
|
else if (cmd == "endsolid")
|
||||||
|
{
|
||||||
|
// Finished with 'endsolid' - find next solid
|
||||||
|
state_ = scanSolid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = perrorParse("facet", cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case scanLoop:
|
||||||
|
{
|
||||||
|
if (cmd == "outer")
|
||||||
|
{
|
||||||
|
// More pedantic would with (tokens_[1] == "loop") too
|
||||||
|
state_ = scanVerts; // Next state
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = perrorParse("outer loop", cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case scanVerts:
|
||||||
|
{
|
||||||
|
if (cmd == "vertex")
|
||||||
|
{
|
||||||
|
if (tokens_.size() > 3)
|
||||||
|
{
|
||||||
|
// Although tokens are not nul-terminated,
|
||||||
|
// they are space delimited and thus good enough for atof()
|
||||||
|
addVertexComponent(tokens_[1].first);
|
||||||
|
addVertexComponent(tokens_[2].first);
|
||||||
|
addVertexComponent(tokens_[3].first);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = "Error parsing vertex value";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cmd == "endloop")
|
||||||
|
{
|
||||||
|
state_ = scanEndFacet; // Next state
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = perrorParse("vertex", cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case scanEndLoop:
|
||||||
|
{
|
||||||
|
if (cmd == "endloop")
|
||||||
|
{
|
||||||
|
state_ = scanEndFacet; // Next state
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = perrorParse("endloop", cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case scanEndFacet:
|
||||||
|
{
|
||||||
|
if (cmd == "endfacet")
|
||||||
|
{
|
||||||
|
endFacet();
|
||||||
|
state_ = scanFacet; // Next facet, or endsolid
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = perrorParse("endfacet", cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case scanEndSolid:
|
||||||
|
{
|
||||||
|
if (cmd == "endsolid")
|
||||||
|
{
|
||||||
|
state_ = scanSolid; // Start over again
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errMsg_ = perrorParse("endsolid", cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (errMsg_.empty());
|
||||||
|
|
||||||
|
// How much still in the bufffer?
|
||||||
|
pending = data + gcount - pe;
|
||||||
|
|
||||||
|
if (pending)
|
||||||
|
{
|
||||||
|
memmove(inbuf, pe, pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gcount < buflen)
|
||||||
|
{
|
||||||
|
break; // done
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errMsg_.empty())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errMsg_.empty())
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< errMsg_ << nl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Member Function
|
||||||
|
//
|
||||||
|
bool Foam::fileFormats::STLReader::readAsciiManual
|
||||||
|
(
|
||||||
|
const fileName& filename
|
||||||
|
)
|
||||||
|
{
|
||||||
|
IFstream is(filename);
|
||||||
|
if (!is)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "file " << filename << " not found"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create with the approximate number of vertices in the STL from file size
|
||||||
|
Detail::STLAsciiParseManual lexer(Foam::fileSize(filename)/400);
|
||||||
|
lexer.execute(is.stdStream());
|
||||||
|
|
||||||
|
transfer(lexer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
1920
src/fileFormats/stl/STLAsciiParseRagel.C
Normal file
1920
src/fileFormats/stl/STLAsciiParseRagel.C
Normal file
File diff suppressed because it is too large
Load Diff
310
src/fileFormats/stl/STLAsciiParseRagel.rl
Normal file
310
src/fileFormats/stl/STLAsciiParseRagel.rl
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
License
|
||||||
|
This file is part of OpenFOAM.
|
||||||
|
|
||||||
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
OpenFOAM 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 General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Description
|
||||||
|
Ragel-based parsing of STL ASCII format.
|
||||||
|
The goto-based finite state machine (FSM) is generated with
|
||||||
|
|
||||||
|
ragel -G2 -o STLAsciiParseRagel.C STLAsciiParseRagel.rl
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "STLAsciiParse.H"
|
||||||
|
#include "STLReader.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/STL_%28file_format%29#ASCII_STL
|
||||||
|
//
|
||||||
|
// Format
|
||||||
|
//
|
||||||
|
// solid [name]
|
||||||
|
//
|
||||||
|
// * where name is an optional string.
|
||||||
|
// * The file continues with any number of triangles,
|
||||||
|
// each represented as follows:
|
||||||
|
//
|
||||||
|
// [color ...]
|
||||||
|
// facet normal ni nj nk
|
||||||
|
// outer loop
|
||||||
|
// vertex v1x v1y v1z
|
||||||
|
// vertex v2x v2y v2z
|
||||||
|
// vertex v3x v3y v3z
|
||||||
|
// endloop
|
||||||
|
// endfacet
|
||||||
|
//
|
||||||
|
// * where each n or v is a floating-point number.
|
||||||
|
// * The file concludes with
|
||||||
|
//
|
||||||
|
// endsolid [name]
|
||||||
|
|
||||||
|
// We take some parsing shortcuts.
|
||||||
|
// - Ignore 'color' lines
|
||||||
|
// - Only look for initial 'facet '. Ignore 'normal ...'
|
||||||
|
// - Ignore name for 'endsolid'
|
||||||
|
//
|
||||||
|
|
||||||
|
// Ragel machine definition
|
||||||
|
// Ragel variables (p, pe, eof, cs, top, stack, ts, te, act) defined later...
|
||||||
|
//
|
||||||
|
// Can use 'variable p xxx;' etc to change these names
|
||||||
|
|
||||||
|
// Define the machine actions
|
||||||
|
%%{
|
||||||
|
machine stlAscii;
|
||||||
|
|
||||||
|
action buffer { tok = p; /* Local token start */ }
|
||||||
|
action nl { ++lineNum_; }
|
||||||
|
|
||||||
|
action bsolid { beginSolid(word::validate(tok, p)); }
|
||||||
|
action bfacet { beginFacet(); }
|
||||||
|
action efacet { endFacet(); }
|
||||||
|
|
||||||
|
action bvertex { resetVertex(); }
|
||||||
|
action vertexCmpt
|
||||||
|
{
|
||||||
|
const char saveC = *p;
|
||||||
|
*p = '\0'; // Make nul-terminated
|
||||||
|
|
||||||
|
addVertexComponent(tok);
|
||||||
|
*p = saveC; // Restore previous character
|
||||||
|
}
|
||||||
|
|
||||||
|
}%%
|
||||||
|
|
||||||
|
|
||||||
|
%%{
|
||||||
|
machine stlAscii;
|
||||||
|
|
||||||
|
white = [ \t\f\r]; # Horizontal whitespace
|
||||||
|
nl = (white* '\n' %nl); # Newline
|
||||||
|
dnl = ([^\n]* '\n' %nl); # Discard up to and including newline
|
||||||
|
|
||||||
|
decimal = ((digit* '.' digit+) | (digit+ '.'?)) ;
|
||||||
|
number = [\-+]? (digit+ | decimal) ([Ee][\-+]? digit+)? ;
|
||||||
|
|
||||||
|
bfacet = space* ("facet"|"FACET") white %bfacet dnl;
|
||||||
|
efacet = space* ("endfacet"|"ENDFACET") %efacet dnl;
|
||||||
|
|
||||||
|
solidName =
|
||||||
|
('' >buffer %bsolid nl)
|
||||||
|
| ((white+ [^\n]*) >buffer %bsolid nl);
|
||||||
|
|
||||||
|
bsolid =
|
||||||
|
space* ("solid"|"SOLID") solidName ;
|
||||||
|
|
||||||
|
esolid = space* ("endsolid"|"ENDSOLID") dnl;
|
||||||
|
|
||||||
|
color = space* ("color"|"COLOR") dnl;
|
||||||
|
|
||||||
|
bloop = space* ("outer" white+ "loop")|("OUTER" white+ "LOOP") dnl;
|
||||||
|
eloop = space* ("endloop"|"ENDLOOP") dnl;
|
||||||
|
|
||||||
|
vertex = space* ("vertex"|"VERTEX")
|
||||||
|
((white+ (number > buffer %vertexCmpt)){3} nl);
|
||||||
|
|
||||||
|
main := space*
|
||||||
|
(
|
||||||
|
bsolid
|
||||||
|
color?
|
||||||
|
( bfacet bloop (vertex)* eloop efacet )*
|
||||||
|
esolid
|
||||||
|
)+ space*;
|
||||||
|
|
||||||
|
}%%
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FSM globals
|
||||||
|
//
|
||||||
|
|
||||||
|
%% write data nofinal;
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace Detail
|
||||||
|
{
|
||||||
|
|
||||||
|
//- A lexer for parsing STL ASCII files.
|
||||||
|
// Returns DynamicList(s) of points and facets (zoneIds).
|
||||||
|
// The facets are within a solid/endsolid grouping
|
||||||
|
class STLAsciiParseRagel
|
||||||
|
:
|
||||||
|
public Detail::STLAsciiParse
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
word startError_;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- From input stream and the approximate number of vertices in the STL
|
||||||
|
STLAsciiParseRagel(const label approxNpoints)
|
||||||
|
:
|
||||||
|
Detail::STLAsciiParse(approxNpoints)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//- Execute lexer
|
||||||
|
void execute(std::istream& is);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Detail
|
||||||
|
} // end of namespace Foam
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
// Length of the input read buffer
|
||||||
|
#define INBUFLEN 16384
|
||||||
|
|
||||||
|
void Foam::Detail::STLAsciiParseRagel::execute(std::istream& is)
|
||||||
|
{
|
||||||
|
if (!is)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cs = code state
|
||||||
|
int cs;
|
||||||
|
|
||||||
|
%%{write init;}%% /* ^^^ FSM initialization here ^^^ */;
|
||||||
|
|
||||||
|
// Local token start
|
||||||
|
char *tok = nullptr;
|
||||||
|
|
||||||
|
// Buffering
|
||||||
|
char inbuf[INBUFLEN];
|
||||||
|
std::streamsize pending = 0;
|
||||||
|
|
||||||
|
// Line-oriented processing loop (as per Ragel pdf example)
|
||||||
|
|
||||||
|
while (is)
|
||||||
|
{
|
||||||
|
if (pending >= INBUFLEN)
|
||||||
|
{
|
||||||
|
// We overfilled the buffer while trying to scan a token...
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "buffer full while scanning near line " << lineNum_ << nl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *data = inbuf + pending; // current data buffer
|
||||||
|
const std::streamsize buflen = INBUFLEN - pending; // space in buffer
|
||||||
|
|
||||||
|
is.read(data, buflen);
|
||||||
|
const std::streamsize gcount = is.gcount();
|
||||||
|
if (!gcount)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// p,pe = Ragel parsing point, parsing end (default naming)
|
||||||
|
// eof = Ragel EOF point (default naming)
|
||||||
|
|
||||||
|
char *p = inbuf;
|
||||||
|
const char *pe = data + gcount;
|
||||||
|
const char *eof = nullptr;
|
||||||
|
if (!is)
|
||||||
|
{
|
||||||
|
eof = pe; // Tag 'pe' as being the EOF for the FSM as well
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line-oriented: search backwards to find last newline
|
||||||
|
{
|
||||||
|
--pe;
|
||||||
|
while (*pe != '\n' && pe >= inbuf)
|
||||||
|
{
|
||||||
|
--pe;
|
||||||
|
}
|
||||||
|
++pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
%%{write exec;}%% /* ^^^ FSM execution here ^^^ */;
|
||||||
|
|
||||||
|
if (%%{write error;}%% == cs)
|
||||||
|
{
|
||||||
|
// FSM failed before finding a token
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "parse error while scanning near line " << lineNum_ << nl;
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
std::string::size_type errLen = (pe - p);
|
||||||
|
if (errLen > 80)
|
||||||
|
{
|
||||||
|
errLen = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "context: " << std::string(p, errLen) << nl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// How much still in the bufffer?
|
||||||
|
pending = data + gcount - pe;
|
||||||
|
|
||||||
|
if (pending)
|
||||||
|
{
|
||||||
|
memmove(inbuf, pe, pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gcount < buflen)
|
||||||
|
{
|
||||||
|
break; // done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Member Function
|
||||||
|
//
|
||||||
|
bool Foam::fileFormats::STLReader::readAsciiRagel
|
||||||
|
(
|
||||||
|
const fileName& filename
|
||||||
|
)
|
||||||
|
{
|
||||||
|
IFstream is(filename);
|
||||||
|
if (!is)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "file " << filename << " not found"
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create with approx number of vertices in the STL (from file size)
|
||||||
|
Detail::STLAsciiParseRagel lexer(Foam::fileSize(filename)/400);
|
||||||
|
lexer.execute(is.stdStream());
|
||||||
|
|
||||||
|
transfer(lexer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -24,14 +24,60 @@ License
|
|||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "STLReader.H"
|
#include "STLReader.H"
|
||||||
|
#include "STLAsciiParse.H"
|
||||||
#include "Map.H"
|
#include "Map.H"
|
||||||
#include "IFstream.H"
|
#include "IFstream.H"
|
||||||
#include "mergePoints.H"
|
#include "mergePoints.H"
|
||||||
|
|
||||||
#undef DEBUG_STLBINARY
|
#undef DEBUG_STLBINARY
|
||||||
|
|
||||||
|
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
int Foam::fileFormats::STLReader::parserType
|
||||||
|
(
|
||||||
|
Foam::debug::optimisationSwitch("fileFormats::stl", 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void Foam::fileFormats::STLReader::transfer
|
||||||
|
(
|
||||||
|
Detail::STLAsciiParse& parsed
|
||||||
|
)
|
||||||
|
{
|
||||||
|
sorted_ = parsed.sorted();
|
||||||
|
|
||||||
|
points_.transfer(parsed.points());
|
||||||
|
zoneIds_.transfer(parsed.facets());
|
||||||
|
names_.transfer(parsed.names());
|
||||||
|
sizes_.transfer(parsed.sizes());
|
||||||
|
|
||||||
|
format_ = STLFormat::ASCII;
|
||||||
|
|
||||||
|
parsed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::fileFormats::STLReader::readASCII
|
||||||
|
(
|
||||||
|
const fileName& filename
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// No runtime selection of parser (only via optimisationSwitch)
|
||||||
|
// this is something that is infrequently changed.
|
||||||
|
if (parserType == 1)
|
||||||
|
{
|
||||||
|
return readAsciiRagel(filename);
|
||||||
|
}
|
||||||
|
else if (parserType == 2)
|
||||||
|
{
|
||||||
|
return readAsciiManual(filename);
|
||||||
|
}
|
||||||
|
return readAsciiFlex(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Foam::fileFormats::STLReader::readBINARY
|
bool Foam::fileFormats::STLReader::readBINARY
|
||||||
(
|
(
|
||||||
const fileName& filename
|
const fileName& filename
|
||||||
@ -189,12 +235,6 @@ Foam::fileFormats::STLReader::STLReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::fileFormats::STLReader::~STLReader()
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
void Foam::fileFormats::STLReader::clear()
|
void Foam::fileFormats::STLReader::clear()
|
||||||
|
|||||||
@ -45,6 +45,15 @@ SourceFiles
|
|||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace Detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
class STLAsciiParse;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace fileFormats
|
namespace fileFormats
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -78,7 +87,19 @@ class STLReader
|
|||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
//- Read ASCII
|
//- Transfer parsed information to normal lists
|
||||||
|
void transfer(Detail::STLAsciiParse& parsed);
|
||||||
|
|
||||||
|
//- Parse/read ASCII using Flex-based parser
|
||||||
|
bool readAsciiFlex(const fileName& filename);
|
||||||
|
|
||||||
|
//- Parse/read ASCII using Ragel-based parser
|
||||||
|
bool readAsciiRagel(const fileName& filename);
|
||||||
|
|
||||||
|
//- Parse/read ASCII using simple handwritten parser
|
||||||
|
bool readAsciiManual(const fileName& filename);
|
||||||
|
|
||||||
|
//- Parse/read ASCII
|
||||||
bool readASCII(const fileName& filename);
|
bool readASCII(const fileName& filename);
|
||||||
|
|
||||||
//- Read BINARY
|
//- Read BINARY
|
||||||
@ -88,15 +109,21 @@ class STLReader
|
|||||||
bool readFile(const fileName& filename, const STLFormat format);
|
bool readFile(const fileName& filename, const STLFormat format);
|
||||||
|
|
||||||
|
|
||||||
//- Disallow default bitwise copy construct
|
//- No copy construct
|
||||||
STLReader(const STLReader&) = delete;
|
STLReader(const STLReader&) = delete;
|
||||||
|
|
||||||
//- Disallow default bitwise assignment
|
//- No copy assignment
|
||||||
void operator=(const STLReader&) = delete;
|
void operator=(const STLReader&) = delete;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// Static Data
|
||||||
|
|
||||||
|
//- ASCII parser types (0=Flex, 1=Ragel, 2=Manual)
|
||||||
|
static int parserType;
|
||||||
|
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
//- Read from file, filling in the information.
|
//- Read from file, filling in the information.
|
||||||
@ -109,7 +136,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
//- Destructor
|
//- Destructor
|
||||||
~STLReader();
|
~STLReader() = default;
|
||||||
|
|
||||||
|
|
||||||
// Member Functions
|
// Member Functions
|
||||||
|
|||||||
@ -82,10 +82,10 @@ class STLsurfaceFormat
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
//- Disallow default bitwise copy construct
|
//- No copy construct
|
||||||
STLsurfaceFormat(const STLsurfaceFormat<Face>&) = delete;
|
STLsurfaceFormat(const STLsurfaceFormat<Face>&) = delete;
|
||||||
|
|
||||||
//- Disallow default bitwise assignment
|
//- No copy assignment
|
||||||
void operator=(const STLsurfaceFormat<Face>&) = delete;
|
void operator=(const STLsurfaceFormat<Face>&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -491,19 +491,30 @@ Foam::triSurface::triSurface
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Foam::triSurface::triSurface(const fileName& name, const scalar scaleFactor)
|
Foam::triSurface::triSurface
|
||||||
|
(
|
||||||
|
const fileName& name,
|
||||||
|
const scalar scaleFactor
|
||||||
|
)
|
||||||
|
:
|
||||||
|
triSurface(name, name.ext(), scaleFactor)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::triSurface::triSurface
|
||||||
|
(
|
||||||
|
const fileName& name,
|
||||||
|
const word& ext,
|
||||||
|
const scalar scaleFactor
|
||||||
|
)
|
||||||
:
|
:
|
||||||
ParentType(List<Face>(), pointField()),
|
ParentType(List<Face>(), pointField()),
|
||||||
patches_(),
|
patches_(),
|
||||||
sortedEdgeFacesPtr_(nullptr),
|
sortedEdgeFacesPtr_(nullptr),
|
||||||
edgeOwnerPtr_(nullptr)
|
edgeOwnerPtr_(nullptr)
|
||||||
{
|
{
|
||||||
const word ext = name.ext();
|
|
||||||
|
|
||||||
read(name, ext);
|
read(name, ext);
|
||||||
|
|
||||||
scalePoints(scaleFactor);
|
scalePoints(scaleFactor);
|
||||||
|
|
||||||
setDefaultPatches();
|
setDefaultPatches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -285,6 +285,14 @@ public:
|
|||||||
// Optional (positive, non-zero) point scaling is possible.
|
// Optional (positive, non-zero) point scaling is possible.
|
||||||
triSurface(const fileName& name, const scalar scaleFactor = -1);
|
triSurface(const fileName& name, const scalar scaleFactor = -1);
|
||||||
|
|
||||||
|
//- Construct from file name (uses extension to determine type)
|
||||||
|
triSurface
|
||||||
|
(
|
||||||
|
const fileName& name,
|
||||||
|
const word& ext,
|
||||||
|
const scalar scaleFactor = -1
|
||||||
|
);
|
||||||
|
|
||||||
//- Construct from Istream
|
//- Construct from Istream
|
||||||
triSurface(Istream& is);
|
triSurface(Istream& is);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user