diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index 2f20fee7e8..4e138824b6 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -74,8 +74,10 @@ primitives/functions/Polynomial/polynomialFunction.C strings = primitives/strings $(strings)/string/string.C $(strings)/string/stringIO.C +$(strings)/string/stringIOList.C $(strings)/word/word.C $(strings)/word/wordIO.C +$(strings)/word/wordIOList.C $(strings)/fileName/fileName.C $(strings)/fileName/fileNameIO.C $(strings)/keyType/keyType.C diff --git a/src/OpenFOAM/primitives/strings/string/stringIOList.C b/src/OpenFOAM/primitives/strings/string/stringIOList.C new file mode 100644 index 0000000000..b69b2d46a3 --- /dev/null +++ b/src/OpenFOAM/primitives/strings/string/stringIOList.C @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ 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 . + +\*---------------------------------------------------------------------------*/ + +#include "stringIOList.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + defineCompoundTypeName(List, stringList); + addCompoundToRunTimeSelectionTable(List, stringList); + + defineTemplateTypeNameAndDebugWithName(stringIOList, "stringList", 0); + defineTemplateTypeNameAndDebugWithName + ( + stringListIOList, + "stringListList", + 0 + ); +} + +// ************************************************************************* // diff --git a/src/OpenFOAM/primitives/strings/string/stringIOList.H b/src/OpenFOAM/primitives/strings/string/stringIOList.H new file mode 100644 index 0000000000..f0d213a5e3 --- /dev/null +++ b/src/OpenFOAM/primitives/strings/string/stringIOList.H @@ -0,0 +1,50 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ 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 . + +Typedef + Foam::stringIOList + +Description + IO of a list of strings + +\*---------------------------------------------------------------------------*/ + +#ifndef stringIOList_H +#define stringIOList_H + +#include "stringList.H" +#include "IOList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + typedef IOList stringIOList; + typedef IOList stringListIOList; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/OpenFOAM/primitives/strings/word/wordIOList.C b/src/OpenFOAM/primitives/strings/word/wordIOList.C new file mode 100644 index 0000000000..dc85ced879 --- /dev/null +++ b/src/OpenFOAM/primitives/strings/word/wordIOList.C @@ -0,0 +1,40 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ 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 . + +\*---------------------------------------------------------------------------*/ + +#include "wordIOList.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + defineCompoundTypeName(List, wordList); + addCompoundToRunTimeSelectionTable(List, wordList); + + defineTemplateTypeNameAndDebugWithName(wordIOList, "wordList", 0); + defineTemplateTypeNameAndDebugWithName(wordListIOList, "wordListList", 0); +} + +// ************************************************************************* // diff --git a/src/OpenFOAM/primitives/strings/word/wordIOList.H b/src/OpenFOAM/primitives/strings/word/wordIOList.H new file mode 100644 index 0000000000..08e2e2cff6 --- /dev/null +++ b/src/OpenFOAM/primitives/strings/word/wordIOList.H @@ -0,0 +1,50 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ 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 . + +Typedef + Foam::wordIOList + +Description + IO of a list of words + +\*---------------------------------------------------------------------------*/ + +#ifndef wordIOList_H +#define wordIOList_H + +#include "wordList.H" +#include "IOList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + typedef IOList wordIOList; + typedef IOList wordListIOList; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.C b/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.C index 457de19108..f0eda7aaa4 100644 --- a/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.C +++ b/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -26,6 +26,9 @@ License #include "VTKedgeFormat.H" #include "OFstream.H" #include "clock.H" +#include "IFstream.H" +#include "vtkUnstructuredReader.H" +#include "Time.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // @@ -72,12 +75,84 @@ void Foam::fileFormats::VTKedgeFormat::writeEdges // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::fileFormats::VTKedgeFormat::VTKedgeFormat() -{} +Foam::fileFormats::VTKedgeFormat::VTKedgeFormat +( + const fileName& filename +) +{ + read(filename); +} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +bool Foam::fileFormats::VTKedgeFormat::read +( + const fileName& filename +) +{ + IFstream is(filename); + if (!is.good()) + { + FatalErrorIn + ( + "fileFormats::VTKedgeFormat::read(const fileName&)" + ) << "Cannot read file " << filename + << exit(FatalError); + } + + // Construct dummy time so we have something to create an objectRegistry + // from + Time dummyTime + ( + "dummyRoot", + "dummyCase", + "system", + "constant", + false // enableFunctionObjects + ); + + // Make dummy object registry + objectRegistry obr + ( + IOobject + ( + "dummy", + dummyTime, + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ) + ); + + // Construct reader to read file + vtkUnstructuredReader reader(obr, is); + + + // Extract lines + storedPoints().transfer(reader.points()); + + label nEdges = 0; + forAll(reader.lines(), lineI) + { + nEdges += reader.lines()[lineI].size()-1; + } + storedEdges().setSize(nEdges); + + nEdges = 0; + forAll(reader.lines(), lineI) + { + const labelList& verts = reader.lines()[lineI]; + for (label i = 1; i < verts.size(); i++) + { + storedEdges()[nEdges++] = edge(verts[i-1], verts[i]); + } + } + + return true; +} + + void Foam::fileFormats::VTKedgeFormat::write ( const fileName& filename, @@ -91,8 +166,7 @@ void Foam::fileFormats::VTKedgeFormat::write ( "fileFormats::VTKedgeFormat::write" "(const fileName&, const edgeMesh&)" - ) - << "Cannot open file for writing " << filename + ) << "Cannot open file for writing " << filename << exit(FatalError); } diff --git a/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.H b/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.H index c26b66465e..2285cf61a0 100644 --- a/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.H +++ b/src/edgeMesh/edgeFormats/vtk/VTKedgeFormat.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -78,10 +78,23 @@ protected: public: + // Constructors - //- Construct null - VTKedgeFormat(); + //- Construct from file name + VTKedgeFormat(const fileName&); + + + // Selectors + + //- Read file and return surface + static autoPtr New(const fileName& name) + { + return autoPtr + ( + new VTKedgeFormat(name) + ); + } //- Destructor @@ -91,16 +104,17 @@ public: // Member Functions - // Write + //- Write surface mesh components by proxy + static void write(const fileName&, const edgeMesh&); - //- Write edgeMesh - static void write(const fileName&, const edgeMesh&); + //- Read from file + virtual bool read(const fileName&); -// //- Write object -// virtual void write(Ostream& os) const -// { -// write(os, *this); -// } + //- Write object file + virtual void write(const fileName& name) const + { + write(name, *this); + } }; diff --git a/src/edgeMesh/edgeFormats/vtk/VTKedgeFormatRunTime.C b/src/edgeMesh/edgeFormats/vtk/VTKedgeFormatRunTime.C index ad902cd46d..3572004026 100644 --- a/src/edgeMesh/edgeFormats/vtk/VTKedgeFormatRunTime.C +++ b/src/edgeMesh/edgeFormats/vtk/VTKedgeFormatRunTime.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -35,6 +35,16 @@ namespace Foam namespace fileFormats { +// read edgeMesh +addNamedToRunTimeSelectionTable +( + edgeMesh, + VTKedgeFormat, + fileExtension, + vtk +); + +// write edgeMesh addNamedToMemberFunctionSelectionTable ( edgeMesh, diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files index a3acab834d..7845ac9312 100644 --- a/src/fileFormats/Make/files +++ b/src/fileFormats/Make/files @@ -1,3 +1,4 @@ +vtk/vtkUnstructuredReader.C nas/NASCore.C starcd/STARCDCore.C diff --git a/src/fileFormats/vtk/vtkUnstructuredReader.C b/src/fileFormats/vtk/vtkUnstructuredReader.C new file mode 100644 index 0000000000..aabedc884b --- /dev/null +++ b/src/fileFormats/vtk/vtkUnstructuredReader.C @@ -0,0 +1,878 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ 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 . + +\*---------------------------------------------------------------------------*/ + +#include "vtkUnstructuredReader.H" +#include "labelIOField.H" +#include "scalarIOField.H" +#include "stringIOList.H" +#include "cellModeller.H" +#include "vectorIOField.H" + +/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */ + +defineTypeNameAndDebug(Foam::vtkUnstructuredReader, 0); + +template<> +const char* +Foam::NamedEnum::names[] = +{ + "int", + "float", + "string" +}; +const Foam::NamedEnum +Foam::vtkUnstructuredReader::vtkDataTypeNames; + + +template<> +const char* +Foam::NamedEnum::names[] = +{ + "FIELD", + "SCALARS", + "VECTORS" +}; +const Foam::NamedEnum +Foam::vtkUnstructuredReader::vtkDataSetTypeNames; + + +template<> +const char* +Foam::NamedEnum::names[] = +{ + "NOMODE", + "UNSTRUCTURED_GRID", + "POLYDATA", + "CELL_DATA", + "POINT_DATA" +}; +const Foam::NamedEnum +Foam::vtkUnstructuredReader::parseModeNames; + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +template +void Foam::vtkUnstructuredReader::readBlock +( + Istream& inFile, + const label n, + List& lst +) const +{ + lst.setSize(n); + forAll(lst, i) + { + inFile >> lst[i]; + } +} + + +void Foam::vtkUnstructuredReader::warnUnhandledType +( + Istream& inFile, + const label type, + labelHashSet& warningGiven +) const +{ + if (warningGiven.insert(type)) + { + IOWarningIn("vtkUnstructuredReader::warnUnhandledType(..)", inFile) + << "Skipping unknown cell type " << type << endl; + } +} + + +// Split cellTypes into cells, faces and lines +void Foam::vtkUnstructuredReader::extractCells +( + Istream& inFile, + const labelList& cellTypes, + const labelList& cellVertData +) +{ + const cellModel& hex = *(cellModeller::lookup("hex")); + const cellModel& prism = *(cellModeller::lookup("prism")); + const cellModel& pyr = *(cellModeller::lookup("pyr")); + const cellModel& tet = *(cellModeller::lookup("tet")); + + labelList tetPoints(4); + labelList pyrPoints(5); + labelList prismPoints(6); + labelList hexPoints(8); + + + cells_.setSize(cellTypes.size()); + faces_.setSize(cellTypes.size()); + lines_.setSize(cellTypes.size()); + + label dataIndex = 0; + label cellI = 0; + label faceI = 0; + label lineI = 0; + + + // To mark whether unhandled type has been visited. + labelHashSet warningGiven; + + forAll(cellTypes, i) + { + switch (cellTypes[i]) + { + case VTK_VERTEX: + { + warnUnhandledType(inFile, cellTypes[i], warningGiven); + label nRead = cellVertData[dataIndex++]; + if (nRead != 1) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 1 for VTK_VERTEX but found " + << nRead << exit(FatalIOError); + } + dataIndex += nRead; + } + break; + + case VTK_POLY_VERTEX: + { + warnUnhandledType(inFile, cellTypes[i], warningGiven); + label nRead = cellVertData[dataIndex++]; + dataIndex += nRead; + } + break; + + case VTK_LINE: + { + //warnUnhandledType(inFile, cellTypes[i], warningGiven); + label nRead = cellVertData[dataIndex++]; + if (nRead != 2) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 2 for VTK_LINE but found " + << nRead << exit(FatalIOError); + } + labelList& segment = lines_[lineI++]; + segment.setSize(2); + segment[0] = cellVertData[dataIndex++]; + segment[1] = cellVertData[dataIndex++]; + } + break; + + case VTK_POLY_LINE: + { + //warnUnhandledType(inFile, cellTypes[i], warningGiven); + label nRead = cellVertData[dataIndex++]; + labelList& segment = lines_[lineI++]; + segment.setSize(nRead); + forAll(segment, i) + { + segment[i] = cellVertData[dataIndex++]; + } + } + break; + + case VTK_TRIANGLE: + { + face& f = faces_[faceI++]; + f.setSize(3); + label nRead = cellVertData[dataIndex++]; + if (nRead != 3) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 3 for VTK_TRIANGLE but found " + << nRead << exit(FatalIOError); + } + f[0] = cellVertData[dataIndex++]; + f[1] = cellVertData[dataIndex++]; + f[2] = cellVertData[dataIndex++]; + } + break; + + case VTK_QUAD: + { + face& f = faces_[faceI++]; + f.setSize(4); + label nRead = cellVertData[dataIndex++]; + if (nRead != 4) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 4 for VTK_QUAD but found " + << nRead << exit(FatalIOError); + } + f[0] = cellVertData[dataIndex++]; + f[1] = cellVertData[dataIndex++]; + f[2] = cellVertData[dataIndex++]; + f[3] = cellVertData[dataIndex++]; + } + break; + + case VTK_POLYGON: + { + face& f = faces_[faceI++]; + label nRead = cellVertData[dataIndex++]; + f.setSize(nRead); + forAll(f, fp) + { + f[fp] = cellVertData[dataIndex++]; + } + } + break; + + case VTK_TETRA: + { + label nRead = cellVertData[dataIndex++]; + if (nRead != 4) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 4 for VTK_TETRA but found " + << nRead << exit(FatalIOError); + } + tetPoints[0] = cellVertData[dataIndex++]; + tetPoints[1] = cellVertData[dataIndex++]; + tetPoints[2] = cellVertData[dataIndex++]; + tetPoints[3] = cellVertData[dataIndex++]; + cells_[cellI++] = cellShape(tet, tetPoints, true); + } + break; + + case VTK_PYRAMID: + { + label nRead = cellVertData[dataIndex++]; + if (nRead != 5) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 5 for VTK_PYRAMID but found " + << nRead << exit(FatalIOError); + } + pyrPoints[0] = cellVertData[dataIndex++]; + pyrPoints[1] = cellVertData[dataIndex++]; + pyrPoints[2] = cellVertData[dataIndex++]; + pyrPoints[3] = cellVertData[dataIndex++]; + pyrPoints[4] = cellVertData[dataIndex++]; + cells_[cellI++] = cellShape(pyr, pyrPoints, true); + } + break; + + case VTK_WEDGE: + { + label nRead = cellVertData[dataIndex++]; + if (nRead != 6) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 6 for VTK_WEDGE but found " + << nRead << exit(FatalIOError); + } + prismPoints[0] = cellVertData[dataIndex++]; + prismPoints[1] = cellVertData[dataIndex++]; + prismPoints[2] = cellVertData[dataIndex++]; + prismPoints[3] = cellVertData[dataIndex++]; + prismPoints[4] = cellVertData[dataIndex++]; + prismPoints[5] = cellVertData[dataIndex++]; + cells_[cellI++] = cellShape(prism, prismPoints, true); + } + break; + + case VTK_HEXAHEDRON: + { + label nRead = cellVertData[dataIndex++]; + if (nRead != 8) + { + FatalIOErrorIn + ( + "vtkUnstructuredReader::extractCells(..)", + inFile + ) << "Expected size 8 for VTK_HEXAHEDRON but found " + << nRead << exit(FatalIOError); + } + hexPoints[0] = cellVertData[dataIndex++]; + hexPoints[1] = cellVertData[dataIndex++]; + hexPoints[2] = cellVertData[dataIndex++]; + hexPoints[3] = cellVertData[dataIndex++]; + hexPoints[4] = cellVertData[dataIndex++]; + hexPoints[5] = cellVertData[dataIndex++]; + hexPoints[6] = cellVertData[dataIndex++]; + hexPoints[7] = cellVertData[dataIndex++]; + cells_[cellI++] = cellShape(hex, hexPoints, true); + } + break; + + default: + warnUnhandledType(inFile, cellTypes[i], warningGiven); + label nRead = cellVertData[dataIndex++]; + dataIndex += nRead; + } + } + + if (debug) + { + Info<< "Read " << cellI << " cells;" << faceI << " faces." << endl; + } + cells_.setSize(cellI); + faces_.setSize(faceI); + lines_.setSize(lineI); +} + + +// Read single field and stores it on the objectRegistry. +void Foam::vtkUnstructuredReader::readField +( + ISstream& inFile, + objectRegistry& obj, + const word& arrayName, + const word& dataType, + const label size +) const +{ + switch (vtkDataTypeNames[dataType]) + { + case VTK_INT: + { + autoPtr fieldVals + ( + new labelIOField + ( + IOobject + ( + arrayName, + "", + obj + ), + size + ) + ); + readBlock(inFile, fieldVals().size(), fieldVals()); + regIOobject::store(fieldVals); + } + break; + + case VTK_FLOAT: + { + autoPtr fieldVals + ( + new scalarIOField + ( + IOobject + ( + arrayName, + "", + obj + ), + size + ) + ); + readBlock(inFile, fieldVals().size(), fieldVals()); + regIOobject::store(fieldVals); + } + break; + + case VTK_STRING: + { + if (debug) + { + Info<< "Reading strings:" << size << endl; + } + autoPtr fieldVals + ( + new stringIOList + ( + IOobject + ( + arrayName, + "", + obj + ), + size + ) + ); + // Consume current line. + inFile.getLine(fieldVals()[0]); + // Read without parsing + forAll(fieldVals(), i) + { + inFile.getLine(fieldVals()[i]); + } + regIOobject::store(fieldVals); + } + break; + + default: + { + IOWarningIn("vtkUnstructuredReader::extractCells(..)", inFile) + << "Unhandled type " << vtkDataTypeNames[dataType] << endl + << "Skipping " << size + << " words." << endl; + scalarField fieldVals; + readBlock(inFile, size, fieldVals); + } + break; + } +} + + +// Reads fields, stores them on the objectRegistry. Returns a list of +// read fields +Foam::wordList Foam::vtkUnstructuredReader::readFieldArray +( + ISstream& inFile, + objectRegistry& obj, + const label wantedSize +) const +{ + DynamicList fields; + + word dataName(inFile); + if (debug) + { + Info<< "dataName:" << dataName << endl; + } + label numArrays(readLabel(inFile)); + if (debug) + { + Pout<< "numArrays:" << numArrays << endl; + } + for (label i = 0; i < numArrays; i++) + { + word arrayName(inFile); + label numComp(readLabel(inFile)); + label numTuples(readLabel(inFile)); + word dataType(inFile); + + if (debug) + { + Info<< "Reading field " << arrayName + << " of " << numTuples << " tuples of rank " << numComp << endl; + } + + if (wantedSize != -1 && numTuples != wantedSize) + { + FatalIOErrorIn("vtkUnstructuredReader::readFieldArray(..)", inFile) + << "Expected " << wantedSize << " tuples but only have " + << numTuples << exit(FatalIOError); + } + + readField + ( + inFile, + obj, + arrayName, + dataType, + numTuples*numComp + ); + fields.append(arrayName); + } + return fields.shrink(); +} + + +Foam::objectRegistry& Foam::vtkUnstructuredReader::selectRegistry +( + const parseMode readMode +) +{ + if (readMode == CELL_DATA) + { + return cellData_; + } + else if (readMode == POINT_DATA) + { + return pointData_; + } + else + { + return otherData_; + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::vtkUnstructuredReader::vtkUnstructuredReader +( + const objectRegistry& obr, + ISstream& inFile +) +: + cellData_(IOobject("cellData", obr)), + pointData_(IOobject("pointData", obr)), + otherData_(IOobject("otherData", obr)) +{ + read(inFile); +} + + +void Foam::vtkUnstructuredReader::read(ISstream& inFile) +{ + inFile.getLine(header_); + if (debug) + { + Info<< "Header : " << header_ << endl; + } + inFile.getLine(title_); + if (debug) + { + Info<< "Title : " << title_ << endl; + } + inFile.getLine(dataType_); + if (debug) + { + Info<< "dataType : " << dataType_ << endl; + } + + parseMode readMode = NOMODE; + label wantedSize = -1; + + + // Temporary storage for vertices of cells. + labelList cellVerts; + + while (inFile.good()) + { + word tag(inFile); + + if (!inFile.good()) + { + break; + } + + if (debug) + { + Info<< "line:" << inFile.lineNumber() + << " tag:" << tag << endl; + } + + if (tag == "DATASET") + { + word geomType(inFile); + if (debug) + { + Info<< "geomType : " << geomType << endl; + } + readMode = parseModeNames[geomType]; + wantedSize = -1; + } + else if (tag == "POINTS") + { + label nPoints(readLabel(inFile)); + points_.setSize(nPoints); ///3); + if (debug) + { + Info<< "Reading " << nPoints << " numbers representing " + << points_.size() << " coordinates." << endl; + } + + word primitiveTag(inFile); + if (primitiveTag != "float") + { + FatalIOErrorIn("vtkUnstructuredReader::read(..)", inFile) + << "Expected 'float' entry but found " + << primitiveTag + << exit(FatalIOError); + } + forAll(points_, i) + { + inFile >> points_[i].x() >> points_[i].y() >> points_[i].z(); + } + } + else if (tag == "CELLS") + { + label nCells(readLabel(inFile)); + label nNumbers(readLabel(inFile)); + if (debug) + { + Info<< "Reading " << nCells << " cells or faces." << endl; + } + readBlock(inFile, nNumbers, cellVerts); + } + else if (tag == "CELL_TYPES") + { + label nCellTypes(readLabel(inFile)); + + labelList cellTypes; + readBlock(inFile, nCellTypes, cellTypes); + + if (cellTypes.size() > 0 && cellVerts.size() == 0) + { + FatalIOErrorIn("vtkUnstructuredReader::read(..)", inFile) + << "Found " << cellTypes.size() + << " cellTypes but no cells." + << exit(FatalIOError); + } + + extractCells(inFile, cellTypes, cellVerts); + cellVerts.clear(); + } + else if (tag == "LINES") + { + label nLines(readLabel(inFile)); + label nNumbers(readLabel(inFile)); + if (debug) + { + Info<< "Reading " << nLines << " lines." << endl; + } + labelList lineVerts; + readBlock(inFile, nNumbers, lineVerts); + lines_.setSize(nLines); + label elemI = 0; + forAll(lines_, lineI) + { + labelList& f = lines_[lineI]; + f.setSize(lineVerts[elemI++]); + forAll(f, fp) + { + f[fp] = lineVerts[elemI++]; + } + } + } + else if (tag == "POLYGONS") + { + // If in polydata mode + + label nFaces(readLabel(inFile)); + label nNumbers(readLabel(inFile)); + if (debug) + { + Info<< "Reading " << nFaces << " faces." << endl; + } + labelList faceVerts; + readBlock(inFile, nNumbers, faceVerts); + faces_.setSize(nFaces); + label elemI = 0; + forAll(faces_, faceI) + { + face& f = faces_[faceI]; + f.setSize(faceVerts[elemI++]); + forAll(f, fp) + { + f[fp] = faceVerts[elemI++]; + } + } + } + else if (tag == "POINT_DATA") + { + readMode = POINT_DATA; + wantedSize = points_.size(); + + label nPoints(readLabel(inFile)); + if (nPoints != wantedSize) + { + FatalIOErrorIn("vtkUnstructuredReader::read(..)", inFile) + << "Reading POINT_DATA : expected " << wantedSize + << " but read " << nPoints << exit(FatalIOError); + } + } + else if (tag == "CELL_DATA") + { + readMode = CELL_DATA; + wantedSize = cells_.size()+faces_.size(); + + label nCells(readLabel(inFile)); + if (nCells != wantedSize) + { + FatalIOErrorIn("vtkUnstructuredReader::read(..)", inFile) + << "Reading CELL_DATA : expected " + << wantedSize + << " but read " << nCells << exit(FatalIOError); + } + } + else if (tag == "FIELD") + { + // wantedSize already set according to type we expected to read. + readFieldArray(inFile, selectRegistry(readMode), wantedSize); + } + else if (tag == "SCALARS") + { + string line; + inFile.getLine(line); + IStringStream is(line); + word dataName(is); + word dataType(is); + //label numComp(readLabel(inFile)); + + if (debug) + { + Info<< "Reading scalar " << dataName + << " of type " << dataType + << " from lookup table" << endl; + } + + word lookupTableTag(inFile); + if (lookupTableTag != "LOOKUP_TABLE") + { + FatalIOErrorIn("vtkUnstructuredReader::read(..)", inFile) + << "Expected tag LOOKUP_TABLE but read " + << lookupTableTag + << exit(FatalIOError); + } + + word lookupTableName(inFile); + + readField + ( + inFile, + selectRegistry(readMode), + dataName, + dataType, + wantedSize//*numComp + ); + } + else if (tag == "VECTORS" || tag == "NORMALS") + { + string line; + inFile.getLine(line); + IStringStream is(line); + word dataName(is); + word dataType(is); + if (debug) + { + Info<< "Reading vector " << dataName + << " of type " << dataType << endl; + } + + objectRegistry& reg = selectRegistry(readMode); + + readField + ( + inFile, + reg, + dataName, + dataType, + 3*wantedSize + ); + + if (vtkDataTypeNames[dataType] == VTK_FLOAT) + { + objectRegistry::iterator iter = reg.find(dataName); + scalarField s(*dynamic_cast(iter())); + reg.erase(iter); + autoPtr fieldVals + ( + new vectorIOField + ( + IOobject + ( + dataName, + "", + reg + ), + s.size()/3 + ) + ); + + label elemI = 0; + forAll(fieldVals(), i) + { + fieldVals()[i].x() = s[elemI++]; + fieldVals()[i].y() = s[elemI++]; + fieldVals()[i].z() = s[elemI++]; + } + regIOobject::store(fieldVals); + } + } + else + { + FatalIOErrorIn("vtkUnstructuredReader::read(..)", inFile) + << "Unsupported tag " + << tag << exit(FatalIOError); + } + } + + if (debug) + { + Info<< "Read points:" << points_.size() + << " cellShapes:" << cells_.size() + << " faces:" << faces_.size() + << " lines:" << lines_.size() + << nl << endl; + + Info<< "Cell fields:" << endl; + printFieldStats(cellData_); + printFieldStats(cellData_); + printFieldStats(cellData_); + printFieldStats(cellData_); + Info<< nl << endl; + + Info<< "Point fields:" << endl; + printFieldStats(pointData_); + printFieldStats(pointData_); + printFieldStats(pointData_); + printFieldStats(pointData_); + Info<< nl << endl; + + Info<< "Other fields:" << endl; + printFieldStats(otherData_); + printFieldStats(otherData_); + printFieldStats(otherData_); + printFieldStats(otherData_); + } +} + + +template +void Foam::vtkUnstructuredReader::printFieldStats +( + const objectRegistry& obj +) const +{ + wordList fieldNames(obj.names(Type::typeName)); + + if (fieldNames.size() > 0) + { + Info<< "Read " << fieldNames.size() << " " << Type::typeName + << " fields:" << endl; + Info<< "Size\tName" << nl + << "----\t----" << endl; + forAll(fieldNames, i) + { + Info<< obj.lookupObject(fieldNames[i]).size() + << "\t" << fieldNames[i] + << endl; + } + Info<< endl; + } +} + + +// ************************************************************************* // diff --git a/src/fileFormats/vtk/vtkUnstructuredReader.H b/src/fileFormats/vtk/vtkUnstructuredReader.H new file mode 100644 index 0000000000..70df667741 --- /dev/null +++ b/src/fileFormats/vtk/vtkUnstructuredReader.H @@ -0,0 +1,332 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ 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 . + +Class + Foam::vtkUnstructuredReader + +Description + Reader for vtk unstructured legacy files + +SourceFiles + vtkUnstructuredReader.C + +\*---------------------------------------------------------------------------*/ + +#ifndef vtkUnstructuredReader_H +#define vtkUnstructuredReader_H + +#include "objectRegistry.H" +#include "cellShapeList.H" +#include "HashSet.H" +#include "NamedEnum.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of friend functions and operators + + +/*---------------------------------------------------------------------------*\ + Class vtkUnstructuredReader Declaration +\*---------------------------------------------------------------------------*/ + +class vtkUnstructuredReader +{ +public: + + // Public data types + + //- Enumeration defining the vtk data types + enum vtkDataType + { + VTK_INT, + VTK_FLOAT, + VTK_STRING + }; + + static const NamedEnum vtkDataTypeNames; + + + //- Enumeration defining the vtk dataset types + enum vtkDataSetType + { + VTK_FIELD, + VTK_SCALARS, + VTK_VECTORS + }; + + static const NamedEnum vtkDataSetTypeNames; + + + //- Enumeration defining the parse mode - what type of data is being + // read + enum parseMode + { + NOMODE, + UNSTRUCTURED_GRID, + POLYDATA, + CELL_DATA, + POINT_DATA + }; + + static const NamedEnum parseModeNames; + + + //- Enumeration defining the cell types + enum vtkTypes + { + VTK_EMPTY_CELL = 0, + VTK_VERTEX = 1, + VTK_POLY_VERTEX = 2, + VTK_LINE = 3, + VTK_POLY_LINE = 4, + VTK_TRIANGLE = 5, + VTK_TRIANGLE_STRIP = 6, + VTK_POLYGON = 7, + VTK_PIXEL = 8, + VTK_QUAD = 9, + VTK_TETRA = 10, + VTK_VOXEL = 11, + VTK_HEXAHEDRON = 12, + VTK_WEDGE = 13, + VTK_PYRAMID = 14, + VTK_PENTAGONAL_PRISM = 15, + VTK_HEXAGONAL_PRISM = 16, + }; + + +private: + + //- Header + string header_; + + //- Title + string title_; + + //- DataType + string dataType_; + + + // Geometry + + //- Points + pointField points_; + + //- 3D cells. + cellShapeList cells_; + + //- 2D cells (=faces) + faceList faces_; + + //- 1D cells (=edges) + labelListList lines_; + + + // Data + + //- cell based fields + objectRegistry cellData_; + + //- point based fields + objectRegistry pointData_; + + //- other fields + objectRegistry otherData_; + + + + // Private Member Functions + + template + void readBlock + ( + Istream& inFile, + const label n, + List& lst + ) const; + + void warnUnhandledType + ( + Istream& inFile, + const label type, + labelHashSet& warningGiven + ) const; + + void extractCells + ( + Istream& inFile, + const labelList& cellTypes, + const labelList& cellVertData + ); + + void readField + ( + ISstream& inFile, + objectRegistry& obj, + const word& arrayName, + const word& dataType, + const label size + ) const; + + wordList readFieldArray + ( + ISstream& inFile, + objectRegistry& obj, + const label wantedSize + ) const; + + objectRegistry& selectRegistry(const parseMode readMode); + + void read(ISstream& inFile); + + //- Dissallow assignment + void operator=(const vtkUnstructuredReader&); + + +public: + + //- Runtime type information + ClassName("vtkUnstructuredReader"); + + // Constructors + + //- Construct from Istream, read all + vtkUnstructuredReader(const objectRegistry& obr, ISstream&); + + // Member Functions + + //- Header + const string header() const + { + return header_; + } + + //- Title + const string& title() const + { + return title_; + } + + //- DataType + const string& dataType() const + { + return dataType_; + } + + + //- Points + const pointField& points() const + { + return points_; + } + + pointField& points() + { + return points_; + } + + //- 3D cells. + const cellShapeList& cells() const + { + return cells_; + } + + cellShapeList& cells() + { + return cells_; + } + + //- 2D cells (=faces) + const faceList& faces() const + { + return faces_; + } + + faceList& faces() + { + return faces_; + } + + //- 1D cells (=open lines) + const labelListList& lines() const + { + return lines_; + } + + labelListList& lines() + { + return lines_; + } + + //- cell based fields + const objectRegistry& cellData() const + { + return cellData_; + } + + objectRegistry& cellData() + { + return cellData_; + } + + //- point based fields + const objectRegistry& pointData() const + { + return pointData_; + } + + objectRegistry& pointData() + { + return pointData_; + } + + //- other fields + const objectRegistry& otherData() const + { + return otherData_; + } + + objectRegistry& otherData() + { + return otherData_; + } + + + //- Debug: print contents of objectRegistry + template + void printFieldStats(const objectRegistry&) const; + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/wallDist/wallPointYPlus/wallPointYPlusI.H b/src/finiteVolume/fvMesh/wallDist/wallPointYPlus/wallPointYPlusI.H index 3eb7ebcaf8..5f7c7bcd6f 100644 --- a/src/finiteVolume/fvMesh/wallDist/wallPointYPlus/wallPointYPlusI.H +++ b/src/finiteVolume/fvMesh/wallDist/wallPointYPlus/wallPointYPlusI.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -42,25 +42,29 @@ inline bool wallPointYPlus::update { scalar dist2 = magSqr(pt - w2.origin()); - scalar diff = distSqr() - dist2; - - if (diff < 0) + if (valid(td)) { - // already nearer to pt - return false; + scalar diff = distSqr() - dist2; + + if (diff < 0) + { + // already nearer to pt + return false; + } + + if ((diff < SMALL) || ((distSqr() > SMALL) && (diff/distSqr() < tol))) + { + // don't propagate small changes + return false; + } } - if ((diff < SMALL) || ((distSqr() > SMALL) && (diff/distSqr() < tol))) - { - // don't propagate small changes - return false; - } - else + + // Either *this is not yet valid or w2 is closer { // only propagate if interesting (i.e. y+ < 100) scalar yPlus = Foam::sqrt(dist2)/w2.data(); - if (yPlus < yPlusCutOff) { // update with new values diff --git a/src/meshTools/cellDist/patchWave/patchDataWave.C b/src/meshTools/cellDist/patchWave/patchDataWave.C index d6ba4bd2bf..2231458e78 100644 --- a/src/meshTools/cellDist/patchWave/patchDataWave.C +++ b/src/meshTools/cellDist/patchWave/patchDataWave.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -101,8 +101,9 @@ Foam::label Foam::patchDataWave::getValues else { // Illegal/unset value. What to do with data? + // Note: mag for now. Should maybe be member of TransferType? - distance_[cellI] = dist; + distance_[cellI] = mag(dist); //cellData_[cellI] = point::max; cellData_[cellI] = cellInfo[cellI].data(); @@ -149,7 +150,7 @@ Foam::label Foam::patchDataWave::getValues { // Illegal/unset value. What to do with data? - patchField[patchFaceI] = dist; + patchField[patchFaceI] = mag(dist); //patchDataField[patchFaceI] = point::max; patchDataField[patchFaceI] = faceInfo[meshFaceI].data(); diff --git a/src/meshTools/cellDist/wallPoint/wallPointDataI.H b/src/meshTools/cellDist/wallPoint/wallPointDataI.H index a9969812bc..3ec9dd9d5b 100644 --- a/src/meshTools/cellDist/wallPoint/wallPointDataI.H +++ b/src/meshTools/cellDist/wallPoint/wallPointDataI.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -43,7 +43,24 @@ inline bool wallPointData::update { scalar dist2 = magSqr(pt - w2.origin()); - if (!valid(td)) + if (valid(td)) + { + scalar diff = distSqr() - dist2; + + if (diff < 0) + { + // already nearer to pt + return false; + } + + if ((diff < SMALL) || ((distSqr() > SMALL) && (diff/distSqr() < tol))) + { + // don't propagate small changes + return false; + } + } + + // Either *this is not yet valid or w2 is closer { // current not yet set so use any value distSqr() = dist2; @@ -52,29 +69,6 @@ inline bool wallPointData::update return true; } - - scalar diff = distSqr() - dist2; - - if (diff < 0) - { - // already nearer to pt - return false; - } - - if ((diff < SMALL) || ((distSqr() > SMALL) && (diff/distSqr() < tol))) - { - // don't propagate small changes - return false; - } - else - { - // update with new values - distSqr() = dist2; - origin() = w2.origin(); - data_ = w2.data(); - - return true; - } } diff --git a/src/meshTools/cellDist/wallPoint/wallPointI.H b/src/meshTools/cellDist/wallPoint/wallPointI.H index f013664849..8cad5f6a76 100644 --- a/src/meshTools/cellDist/wallPoint/wallPointI.H +++ b/src/meshTools/cellDist/wallPoint/wallPointI.H @@ -85,7 +85,7 @@ inline bool Foam::wallPoint::update inline Foam::wallPoint::wallPoint() : origin_(point::max), - distSqr_(GREAT) + distSqr_(-GREAT) {} diff --git a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C index 8f0c9cf380..3dad786857 100644 --- a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C +++ b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -24,6 +24,8 @@ License \*---------------------------------------------------------------------------*/ #include "VTKsurfaceFormat.H" +#include "vtkUnstructuredReader.H" +#include "scalarIOField.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // @@ -50,12 +52,159 @@ void Foam::fileFormats::VTKsurfaceFormat::writeHeaderPolygons // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // template -Foam::fileFormats::VTKsurfaceFormat::VTKsurfaceFormat() -{} +Foam::fileFormats::VTKsurfaceFormat::VTKsurfaceFormat +( + const fileName& filename +) +{ + read(filename); +} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +template +bool Foam::fileFormats::VTKsurfaceFormat::read +( + const fileName& filename +) +{ + const bool mustTriangulate = this->isTri(); + this->clear(); + + IFstream is(filename); + if (!is.good()) + { + FatalErrorIn + ( + "fileFormats::VTKsurfaceFormat::read(const fileName&)" + ) << "Cannot read file " << filename + << exit(FatalError); + } + + // assume that the groups are not intermixed + bool sorted = true; + + + // Construct dummy time so we have something to create an objectRegistry + // from + Time dummyTime + ( + "dummyRoot", + "dummyCase", + "system", + "constant", + false // enableFunctionObjects + ); + + // Make dummy object registry + objectRegistry obr + ( + IOobject + ( + "dummy", + dummyTime, + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ) + ); + + // Read all + vtkUnstructuredReader reader(obr, is); + const faceList& faces = reader.faces(); + + // Assume all faces in zone0 unless a region field is present + labelList zones(faces.size(), 0); + if (reader.cellData().foundObject("region")) + { + const scalarIOField& region = + reader.cellData().lookupObject + ( + "region" + ); + forAll(region, i) + { + zones[i] = label(region[i]); + } + } + + // Create zone names + const label nZones = max(zones)+1; + wordList zoneNames(nZones); + forAll(zoneNames, i) + { + zoneNames[i] = "zone" + Foam::name(i); + } + + + // See if needs triangulation + label nTri = 0; + if (mustTriangulate) + { + forAll(faces, faceI) + { + nTri += faces[faceI].size()-2; + } + } + + if (nTri > 0) + { + DynamicList dynFaces(nTri); + DynamicList