mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
BUG: spurious empty surface zones added (fixes #706)
- problems were introduced by the change ee252307d3 (issue #686).
Affected reading of OBJ files.
The fallback zone (used to catch unnamed groups/zones), which was
previously filtered away when not needed. Now handle more explicitly.
ENH: use stringOps::split and low-level read{Label,Scalar} for parsing OBJ file
This commit is contained in:
@ -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-2017 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -27,8 +27,55 @@ License
|
|||||||
#include "clock.H"
|
#include "clock.H"
|
||||||
#include "Fstream.H"
|
#include "Fstream.H"
|
||||||
#include "Ostream.H"
|
#include "Ostream.H"
|
||||||
#include "StringStream.H"
|
#include "stringOps.H"
|
||||||
#include "ListOps.H"
|
|
||||||
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
// Token list with one of the following:
|
||||||
|
// f v1 v2 v3 ...
|
||||||
|
// f v1/vt1 v2/vt2 v3/vt3 ...
|
||||||
|
// l v1 v2 v3 ...
|
||||||
|
// l v1/vt1 v2/vt2 v3/vt3 ...
|
||||||
|
static label readObjVertices
|
||||||
|
(
|
||||||
|
const SubStrings<string>& tokens,
|
||||||
|
DynamicList<label>& verts
|
||||||
|
)
|
||||||
|
{
|
||||||
|
verts.clear();
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
for (const auto& tok : tokens)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
// skip initial "f" or "l"
|
||||||
|
first = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string vrtSpec(tok);
|
||||||
|
const auto slash = vrtSpec.find('/');
|
||||||
|
|
||||||
|
const label vertId =
|
||||||
|
(
|
||||||
|
slash != string::npos
|
||||||
|
? readLabel(vrtSpec.substr(0, slash))
|
||||||
|
: readLabel(vrtSpec)
|
||||||
|
);
|
||||||
|
|
||||||
|
verts.append(vertId - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return verts.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -43,56 +90,6 @@ Foam::fileFormats::OBJedgeFormat::OBJedgeFormat
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
void Foam::fileFormats::OBJedgeFormat::readVertices
|
|
||||||
(
|
|
||||||
const string& line,
|
|
||||||
string::size_type& endNum,
|
|
||||||
DynamicList<label>& dynVertices
|
|
||||||
)
|
|
||||||
{
|
|
||||||
dynVertices.clear();
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
string::size_type startNum =
|
|
||||||
line.find_first_not_of(' ', endNum);
|
|
||||||
|
|
||||||
if (startNum == string::npos)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
endNum = line.find(' ', startNum);
|
|
||||||
|
|
||||||
string vertexSpec;
|
|
||||||
if (endNum != string::npos)
|
|
||||||
{
|
|
||||||
vertexSpec = line.substr(startNum, endNum-startNum);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vertexSpec = line.substr(startNum, line.size() - startNum);
|
|
||||||
}
|
|
||||||
|
|
||||||
string::size_type slashPos = vertexSpec.find('/');
|
|
||||||
|
|
||||||
label vertI = 0;
|
|
||||||
if (slashPos != string::npos)
|
|
||||||
{
|
|
||||||
IStringStream intStream(vertexSpec.substr(0, slashPos));
|
|
||||||
|
|
||||||
intStream >> vertI;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IStringStream intStream(vertexSpec);
|
|
||||||
|
|
||||||
intStream >> vertI;
|
|
||||||
}
|
|
||||||
dynVertices.append(vertI - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
|
bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
@ -106,97 +103,97 @@ bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DynamicList<point> dynPoints;
|
DynamicList<point> dynPoints;
|
||||||
|
DynamicList<label> dynVerts;
|
||||||
DynamicList<edge> dynEdges;
|
DynamicList<edge> dynEdges;
|
||||||
DynamicList<label> dynUsedPoints;
|
DynamicList<label> dynUsedPoints;
|
||||||
|
|
||||||
DynamicList<label> dynVertices;
|
|
||||||
|
|
||||||
while (is.good())
|
while (is.good())
|
||||||
{
|
{
|
||||||
string line = this->getLineNoComment(is);
|
string line = this->getLineNoComment(is);
|
||||||
|
|
||||||
// Handle continuations
|
// Line continuations
|
||||||
if (line.removeEnd("\\"))
|
while (line.removeEnd("\\"))
|
||||||
{
|
{
|
||||||
line += this->getLineNoComment(is);
|
line += this->getLineNoComment(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read first word
|
const SubStrings<string> tokens = stringOps::splitSpace(line);
|
||||||
IStringStream lineStream(line);
|
|
||||||
word cmd;
|
// Require command and some arguments
|
||||||
lineStream >> cmd;
|
if (tokens.size() < 2)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const word cmd = word::validate(tokens[0]);
|
||||||
|
|
||||||
if (cmd == "v")
|
if (cmd == "v")
|
||||||
{
|
{
|
||||||
scalar x, y, z;
|
// Vertex
|
||||||
lineStream >> x >> y >> z;
|
// v x y z
|
||||||
|
|
||||||
|
dynPoints.append
|
||||||
|
(
|
||||||
|
point
|
||||||
|
(
|
||||||
|
readScalar(tokens[1]),
|
||||||
|
readScalar(tokens[2]),
|
||||||
|
readScalar(tokens[3])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
dynPoints.append(point(x, y, z));
|
|
||||||
dynUsedPoints.append(-1);
|
dynUsedPoints.append(-1);
|
||||||
}
|
}
|
||||||
else if (cmd == "l")
|
else if (cmd == "l")
|
||||||
{
|
{
|
||||||
// Assume 'l' is followed by space.
|
// Line
|
||||||
string::size_type endNum = 1;
|
// l v1 v2 v3 ...
|
||||||
|
// OR
|
||||||
|
// l v1/vt1 v2/vt2 v3/vt3 ...
|
||||||
|
|
||||||
readVertices
|
readObjVertices(tokens, dynVerts);
|
||||||
(
|
|
||||||
line,
|
|
||||||
endNum,
|
|
||||||
dynVertices
|
|
||||||
);
|
|
||||||
|
|
||||||
|
for (label i = 1; i < dynVerts.size(); i++)
|
||||||
for (label i = 1; i < dynVertices.size(); i++)
|
|
||||||
{
|
{
|
||||||
edge edgeRead(dynVertices[i-1], dynVertices[i]);
|
const edge e(dynVerts[i-1], dynVerts[i]);
|
||||||
|
dynEdges.append(e);
|
||||||
|
|
||||||
dynUsedPoints[edgeRead[0]] = edgeRead[0];
|
dynUsedPoints[e[0]] = e[0];
|
||||||
dynUsedPoints[edgeRead[1]] = edgeRead[1];
|
dynUsedPoints[e[1]] = e[1];
|
||||||
|
|
||||||
dynEdges.append(edgeRead);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cmd == "f")
|
else if (cmd == "f")
|
||||||
{
|
{
|
||||||
// Support for faces with 2 vertices
|
// Face - support for faces with 2 vertices
|
||||||
|
|
||||||
// Assume 'f' is followed by space.
|
// f v1 v2 v3 ...
|
||||||
string::size_type endNum = 1;
|
// OR
|
||||||
|
// f v1/vt1 v2/vt2 v3/vt3 ...
|
||||||
|
|
||||||
readVertices
|
if (readObjVertices(tokens, dynVerts) == 2)
|
||||||
(
|
|
||||||
line,
|
|
||||||
endNum,
|
|
||||||
dynVertices
|
|
||||||
);
|
|
||||||
|
|
||||||
if (dynVertices.size() == 2)
|
|
||||||
{
|
{
|
||||||
for (label i = 1; i < dynVertices.size(); i++)
|
for (label i = 1; i < dynVerts.size(); i++)
|
||||||
{
|
{
|
||||||
edge edgeRead(dynVertices[i-1], dynVertices[i]);
|
const edge e(dynVerts[i-1], dynVerts[i]);
|
||||||
|
dynEdges.append(e);
|
||||||
|
|
||||||
dynUsedPoints[edgeRead[0]] = edgeRead[0];
|
dynUsedPoints[e[0]] = e[0];
|
||||||
dynUsedPoints[edgeRead[1]] = edgeRead[1];
|
dynUsedPoints[e[1]] = e[1];
|
||||||
|
|
||||||
dynEdges.append(edgeRead);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cull unused points
|
// Cull unused points
|
||||||
label nUsed = 0;
|
label nUsed = 0;
|
||||||
|
|
||||||
forAll(dynPoints, pointi)
|
forAll(dynPoints, pointi)
|
||||||
{
|
{
|
||||||
if (dynUsedPoints[pointi] >= 0)
|
if (dynUsedPoints[pointi] >= 0)
|
||||||
{
|
{
|
||||||
if (nUsed != pointi)
|
if (nUsed != pointi)
|
||||||
{
|
{
|
||||||
dynPoints[nUsed] = dynPoints[pointi];
|
dynPoints[nUsed] = std::move(dynPoints[pointi]);
|
||||||
dynUsedPoints[pointi] = nUsed; // new position
|
dynUsedPoints[pointi] = nUsed; // The new list location
|
||||||
}
|
}
|
||||||
++nUsed;
|
++nUsed;
|
||||||
}
|
}
|
||||||
@ -204,16 +201,14 @@ bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
|
|||||||
|
|
||||||
dynPoints.setSize(nUsed);
|
dynPoints.setSize(nUsed);
|
||||||
|
|
||||||
// transfer to normal lists
|
// Transfer to normal lists
|
||||||
storedPoints().transfer(dynPoints);
|
storedPoints().transfer(dynPoints);
|
||||||
|
|
||||||
// renumber edge vertices
|
// Renumber edge vertices
|
||||||
if (nUsed != dynUsedPoints.size())
|
if (nUsed != dynUsedPoints.size())
|
||||||
{
|
{
|
||||||
forAll(dynEdges, edgeI)
|
for (edge& e : dynEdges)
|
||||||
{
|
{
|
||||||
edge& e = dynEdges[edgeI];
|
|
||||||
|
|
||||||
e[0] = dynUsedPoints[e[0]];
|
e[0] = dynUsedPoints[e[0]];
|
||||||
e[1] = dynUsedPoints[e[1]];
|
e[1] = dynUsedPoints[e[1]];
|
||||||
}
|
}
|
||||||
@ -252,10 +247,8 @@ void Foam::fileFormats::OBJedgeFormat::write
|
|||||||
<< "# <points count=\"" << pointLst.size() << "\">" << nl;
|
<< "# <points count=\"" << pointLst.size() << "\">" << nl;
|
||||||
|
|
||||||
// Write vertex coords
|
// Write vertex coords
|
||||||
forAll(pointLst, ptI)
|
for (const point& p : pointLst)
|
||||||
{
|
{
|
||||||
const point& p = pointLst[ptI];
|
|
||||||
|
|
||||||
os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
|
os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,10 +257,8 @@ void Foam::fileFormats::OBJedgeFormat::write
|
|||||||
<< "# <edges count=\"" << edgeLst.size() << "\">" << endl;
|
<< "# <edges count=\"" << edgeLst.size() << "\">" << endl;
|
||||||
|
|
||||||
// Write line connectivity
|
// Write line connectivity
|
||||||
forAll(edgeLst, edgeI)
|
for (const edge& e : edgeLst)
|
||||||
{
|
{
|
||||||
const edge& e = edgeLst[edgeI];
|
|
||||||
|
|
||||||
os << "l " << (e[0] + 1) << " " << (e[1] + 1) << nl;
|
os << "l " << (e[0] + 1) << " " << (e[1] + 1) << nl;
|
||||||
}
|
}
|
||||||
os << "# </edges>" << endl;
|
os << "# </edges>" << endl;
|
||||||
|
|||||||
@ -58,18 +58,11 @@ class OBJedgeFormat
|
|||||||
{
|
{
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
void readVertices
|
|
||||||
(
|
|
||||||
const string& line,
|
|
||||||
string::size_type& endNum,
|
|
||||||
DynamicList<label>& dynVertices
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Disallow default bitwise copy construct
|
//- Disallow default bitwise copy construct
|
||||||
OBJedgeFormat(const OBJedgeFormat&);
|
OBJedgeFormat(const OBJedgeFormat&) = delete;
|
||||||
|
|
||||||
//- Disallow default bitwise assignment
|
//- Disallow default bitwise assignment
|
||||||
void operator=(const OBJedgeFormat&);
|
void operator=(const OBJedgeFormat&) = delete;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -93,8 +86,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
//- Destructor
|
//- Destructor
|
||||||
virtual ~OBJedgeFormat()
|
virtual ~OBJedgeFormat() = default;
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
// Member Functions
|
// Member Functions
|
||||||
|
|||||||
@ -117,12 +117,12 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
|
|||||||
DynamicList<Face> dynFaces;
|
DynamicList<Face> dynFaces;
|
||||||
DynamicList<label> dynZones;
|
DynamicList<label> dynZones;
|
||||||
DynamicList<label> dynSizes;
|
DynamicList<label> dynSizes;
|
||||||
|
|
||||||
Map<label> zoneLookup;
|
Map<label> zoneLookup;
|
||||||
|
|
||||||
// assume the types are not intermixed
|
// Assume that the groups are not intermixed
|
||||||
// leave faces that didn't have a group in 0
|
label zoneId = 0;
|
||||||
bool sorted = true;
|
bool sorted = true;
|
||||||
label zoneI = 0;
|
|
||||||
|
|
||||||
// Name for face group
|
// Name for face group
|
||||||
Map<word> nameLookup;
|
Map<word> nameLookup;
|
||||||
@ -139,7 +139,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
|
|||||||
|
|
||||||
while (is.good())
|
while (is.good())
|
||||||
{
|
{
|
||||||
string::size_type linei = 0; // parsing position within current line
|
string::size_type linei = 0; // Parsing position within current line
|
||||||
string line;
|
string line;
|
||||||
is.getLine(line);
|
is.getLine(line);
|
||||||
|
|
||||||
@ -221,74 +221,74 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
|
|||||||
{
|
{
|
||||||
(void) nextNasField(line, linei, 8); // 8-16
|
(void) nextNasField(line, linei, 8); // 8-16
|
||||||
label groupId = readLabel(nextNasField(line, linei, 8)); // 16-24
|
label groupId = readLabel(nextNasField(line, linei, 8)); // 16-24
|
||||||
label a = readLabel(nextNasField(line, linei, 8)); // 24-32
|
const auto a = readLabel(nextNasField(line, linei, 8)); // 24-32
|
||||||
label b = readLabel(nextNasField(line, linei, 8)); // 32-40
|
const auto b = readLabel(nextNasField(line, linei, 8)); // 32-40
|
||||||
label c = readLabel(nextNasField(line, linei, 8)); // 40-48
|
const auto c = readLabel(nextNasField(line, linei, 8)); // 40-48
|
||||||
|
|
||||||
// Convert groupId into zoneId
|
// Convert groupId into zoneId
|
||||||
const auto fnd = zoneLookup.cfind(groupId);
|
const auto iterZone = zoneLookup.cfind(groupId);
|
||||||
if (fnd.found())
|
if (iterZone.found())
|
||||||
{
|
{
|
||||||
if (zoneI != fnd())
|
if (zoneId != *iterZone)
|
||||||
{
|
{
|
||||||
// pshell types are intermixed
|
// pshell types are intermixed
|
||||||
sorted = false;
|
sorted = false;
|
||||||
}
|
}
|
||||||
zoneI = fnd();
|
zoneId = *iterZone;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zoneI = dynSizes.size();
|
zoneId = dynSizes.size();
|
||||||
zoneLookup.insert(groupId, zoneI);
|
zoneLookup.insert(groupId, zoneId);
|
||||||
dynSizes.append(0);
|
dynSizes.append(0);
|
||||||
// Info<< "zone" << zoneI << " => group " << groupId <<endl;
|
// Info<< "zone" << zoneId << " => group " << groupId <<nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
dynFaces.append(Face{a, b, c});
|
dynFaces.append(Face{a, b, c});
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynSizes[zoneI]++;
|
dynSizes[zoneId]++;
|
||||||
}
|
}
|
||||||
else if (cmd == "CQUAD4")
|
else if (cmd == "CQUAD4")
|
||||||
{
|
{
|
||||||
(void) nextNasField(line, linei, 8); // 8-16
|
(void) nextNasField(line, linei, 8); // 8-16
|
||||||
label groupId = readLabel(nextNasField(line, linei, 8)); // 16-24
|
label groupId = readLabel(nextNasField(line, linei, 8)); // 16-24
|
||||||
label a = readLabel(nextNasField(line, linei, 8)); // 24-32
|
const auto a = readLabel(nextNasField(line, linei, 8)); // 24-32
|
||||||
label b = readLabel(nextNasField(line, linei, 8)); // 32-40
|
const auto b = readLabel(nextNasField(line, linei, 8)); // 32-40
|
||||||
label c = readLabel(nextNasField(line, linei, 8)); // 40-48
|
const auto c = readLabel(nextNasField(line, linei, 8)); // 40-48
|
||||||
label d = readLabel(nextNasField(line, linei, 8)); // 48-56
|
const auto d = readLabel(nextNasField(line, linei, 8)); // 48-56
|
||||||
|
|
||||||
// Convert groupID into zoneId
|
// Convert groupId into zoneId
|
||||||
const auto fnd = zoneLookup.cfind(groupId);
|
const auto iterZone = zoneLookup.cfind(groupId);
|
||||||
if (fnd.found())
|
if (iterZone.found())
|
||||||
{
|
{
|
||||||
if (zoneI != fnd())
|
if (zoneId != *iterZone)
|
||||||
{
|
{
|
||||||
// pshell types are intermixed
|
// pshell types are intermixed
|
||||||
sorted = false;
|
sorted = false;
|
||||||
}
|
}
|
||||||
zoneI = fnd();
|
zoneId = *iterZone;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zoneI = dynSizes.size();
|
zoneId = dynSizes.size();
|
||||||
zoneLookup.insert(groupId, zoneI);
|
zoneLookup.insert(groupId, zoneId);
|
||||||
dynSizes.append(0);
|
dynSizes.append(0);
|
||||||
// Info<< "zone" << zoneI << " => group " << groupId <<endl;
|
// Info<< "zone" << zoneId << " => group " << groupId <<nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (faceTraits<Face>::isTri())
|
if (faceTraits<Face>::isTri())
|
||||||
{
|
{
|
||||||
dynFaces.append(Face{a, b, c});
|
dynFaces.append(Face{a, b, c});
|
||||||
dynFaces.append(Face{c, d, a});
|
dynFaces.append(Face{c, d, a});
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynSizes[zoneI] += 2;
|
dynSizes[zoneId] += 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dynFaces.append(Face{a,b,c,d});
|
dynFaces.append(Face{a,b,c,d});
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynSizes[zoneI]++;
|
dynSizes[zoneId]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cmd == "GRID")
|
else if (cmd == "GRID")
|
||||||
@ -388,10 +388,10 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
|
|||||||
const label groupId = iter.key();
|
const label groupId = iter.key();
|
||||||
const label zoneId = iter.object();
|
const label zoneId = iter.object();
|
||||||
|
|
||||||
const auto fnd = nameLookup.cfind(groupId);
|
const auto iterName = nameLookup.cfind(groupId);
|
||||||
if (fnd.found())
|
if (iterName.found())
|
||||||
{
|
{
|
||||||
names[zoneId] = fnd();
|
names[zoneId] = *iterName;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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.
|
||||||
@ -26,8 +26,7 @@ License
|
|||||||
#include "OBJsurfaceFormat.H"
|
#include "OBJsurfaceFormat.H"
|
||||||
#include "clock.H"
|
#include "clock.H"
|
||||||
#include "Fstream.H"
|
#include "Fstream.H"
|
||||||
#include "StringStream.H"
|
#include "stringOps.H"
|
||||||
#include "ListOps.H"
|
|
||||||
#include "faceTraits.H"
|
#include "faceTraits.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
@ -60,115 +59,123 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
|
|||||||
<< exit(FatalError);
|
<< exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume that the groups are not intermixed
|
// Assume that the groups are not intermixed
|
||||||
|
// Place faces without a group in zone0.
|
||||||
|
// zoneId = -1 to signal uninitialized
|
||||||
|
label zoneId = -1;
|
||||||
bool sorted = true;
|
bool sorted = true;
|
||||||
|
|
||||||
DynamicList<point> dynPoints;
|
DynamicList<point> dynPoints;
|
||||||
|
DynamicList<label> dynVerts;
|
||||||
DynamicList<Face> dynFaces;
|
DynamicList<Face> dynFaces;
|
||||||
DynamicList<label> dynZones;
|
|
||||||
DynamicList<word> dynNames;
|
|
||||||
DynamicList<label> dynSizes;
|
|
||||||
HashTable<label> lookup;
|
|
||||||
|
|
||||||
// place faces without a group in zone0
|
DynamicList<word> dynNames;
|
||||||
label zoneI = 0;
|
DynamicList<label> dynZones;
|
||||||
lookup.insert("zone0", zoneI);
|
DynamicList<label> dynSizes;
|
||||||
dynNames.append("zone0");
|
|
||||||
dynSizes.append(0);
|
HashTable<label> groupLookup;
|
||||||
|
|
||||||
while (is.good())
|
while (is.good())
|
||||||
{
|
{
|
||||||
string line = this->getLineNoComment(is);
|
string line = this->getLineNoComment(is);
|
||||||
|
|
||||||
// Handle continuations
|
// Line continuations
|
||||||
if (line.removeEnd("\\"))
|
while (line.removeEnd("\\"))
|
||||||
{
|
{
|
||||||
line += this->getLineNoComment(is);
|
line += this->getLineNoComment(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read first word
|
const SubStrings<string> tokens = stringOps::splitSpace(line);
|
||||||
IStringStream lineStream(line);
|
|
||||||
word cmd;
|
// Require command and some arguments
|
||||||
lineStream >> cmd;
|
if (tokens.size() < 2)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const word cmd = word::validate(tokens[0]);
|
||||||
|
|
||||||
if (cmd == "v")
|
if (cmd == "v")
|
||||||
{
|
{
|
||||||
scalar x, y, z;
|
// Vertex
|
||||||
lineStream >> x >> y >> z;
|
// v x y z
|
||||||
dynPoints.append(point(x, y, z));
|
|
||||||
|
dynPoints.append
|
||||||
|
(
|
||||||
|
point
|
||||||
|
(
|
||||||
|
readScalar(tokens[1]),
|
||||||
|
readScalar(tokens[2]),
|
||||||
|
readScalar(tokens[3])
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (cmd == "g")
|
else if (cmd == "g")
|
||||||
{
|
{
|
||||||
word name;
|
// Grouping
|
||||||
lineStream >> name;
|
// g name
|
||||||
|
|
||||||
HashTable<label>::const_iterator fnd = lookup.find(name);
|
const word groupName = word::validate(tokens[1]);
|
||||||
if (fnd != lookup.end())
|
const auto iterGroup = groupLookup.cfind(groupName);
|
||||||
|
|
||||||
|
if (iterGroup.found())
|
||||||
{
|
{
|
||||||
if (zoneI != fnd())
|
if (zoneId != *iterGroup)
|
||||||
{
|
{
|
||||||
// group appeared out of order
|
sorted = false; // group appeared out of order
|
||||||
sorted = false;
|
|
||||||
}
|
}
|
||||||
zoneI = fnd();
|
zoneId = *iterGroup;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zoneI = dynSizes.size();
|
zoneId = dynSizes.size();
|
||||||
lookup.insert(name, zoneI);
|
groupLookup.insert(groupName, zoneId);
|
||||||
dynNames.append(name);
|
dynNames.append(groupName);
|
||||||
dynSizes.append(0);
|
dynSizes.append(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cmd == "f")
|
else if (cmd == "f")
|
||||||
{
|
{
|
||||||
DynamicList<label> dynVertices;
|
// Face
|
||||||
|
// f v1 v2 v3 ...
|
||||||
|
// OR
|
||||||
|
// f v1/vt1 v2/vt2 v3/vt3 ...
|
||||||
|
|
||||||
// Assume 'f' is followed by space.
|
// Ensure it has as valid grouping
|
||||||
string::size_type endNum = 1;
|
if (zoneId < 0)
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
string::size_type startNum =
|
zoneId = 0;
|
||||||
line.find_first_not_of(' ', endNum);
|
groupLookup.insert("zone0", 0);
|
||||||
|
dynNames.append("zone0");
|
||||||
if (startNum == string::npos)
|
dynSizes.append(0);
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
endNum = line.find(' ', startNum);
|
dynVerts.clear();
|
||||||
|
|
||||||
string vertexSpec;
|
bool first = true;
|
||||||
if (endNum != string::npos)
|
for (const auto& tok : tokens)
|
||||||
{
|
{
|
||||||
vertexSpec = line.substr(startNum, endNum-startNum);
|
if (first)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
vertexSpec = line.substr(startNum);
|
// skip initial "f" or "l"
|
||||||
|
first = false;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string::size_type slashPos = vertexSpec.find('/');
|
const string vrtSpec(tok);
|
||||||
|
const auto slash = vrtSpec.find('/');
|
||||||
|
|
||||||
label vertI = 0;
|
const label vertId =
|
||||||
if (slashPos != string::npos)
|
(
|
||||||
{
|
slash != string::npos
|
||||||
IStringStream intStream(vertexSpec.substr(0, slashPos));
|
? readLabel(vrtSpec.substr(0, slash))
|
||||||
|
: readLabel(vrtSpec)
|
||||||
|
);
|
||||||
|
|
||||||
intStream >> vertI;
|
dynVerts.append(vertId - 1);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
IStringStream intStream(vertexSpec);
|
|
||||||
|
|
||||||
intStream >> vertI;
|
const labelUList& f = dynVerts;
|
||||||
}
|
|
||||||
dynVertices.append(vertI - 1);
|
|
||||||
}
|
|
||||||
dynVertices.shrink();
|
|
||||||
|
|
||||||
labelUList& f = static_cast<labelUList&>(dynVertices);
|
|
||||||
|
|
||||||
if (faceTraits<Face>::isTri() && f.size() > 3)
|
if (faceTraits<Face>::isTri() && f.size() > 3)
|
||||||
{
|
{
|
||||||
@ -179,21 +186,21 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
|
|||||||
const label fp2 = f.fcIndex(fp1);
|
const label fp2 = f.fcIndex(fp1);
|
||||||
|
|
||||||
dynFaces.append(Face{f[0], f[fp1], f[fp2]});
|
dynFaces.append(Face{f[0], f[fp1], f[fp2]});
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynSizes[zoneI]++;
|
dynSizes[zoneId]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (f.size() >= 3)
|
||||||
{
|
{
|
||||||
dynFaces.append(Face(f));
|
dynFaces.append(Face(f));
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynSizes[zoneI]++;
|
dynSizes[zoneId]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// transfer to normal lists
|
// Transfer to normal lists
|
||||||
this->storedPoints().transfer(dynPoints);
|
this->storedPoints().transfer(dynPoints);
|
||||||
|
|
||||||
this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
|
this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
|
||||||
@ -282,9 +289,9 @@ void Foam::fileFormats::OBJsurfaceFormat<Face>::write
|
|||||||
const Face& f = faceLst[faceMap[faceIndex++]];
|
const Face& f = faceLst[faceMap[faceIndex++]];
|
||||||
|
|
||||||
os << 'f';
|
os << 'f';
|
||||||
forAll(f, fp)
|
for (const label verti : f)
|
||||||
{
|
{
|
||||||
os << ' ' << f[fp] + 1;
|
os << ' ' << verti + 1;
|
||||||
}
|
}
|
||||||
os << nl;
|
os << nl;
|
||||||
}
|
}
|
||||||
@ -296,9 +303,9 @@ void Foam::fileFormats::OBJsurfaceFormat<Face>::write
|
|||||||
const Face& f = faceLst[faceIndex++];
|
const Face& f = faceLst[faceIndex++];
|
||||||
|
|
||||||
os << 'f';
|
os << 'f';
|
||||||
forAll(f, fp)
|
for (const label verti : f)
|
||||||
{
|
{
|
||||||
os << ' ' << f[fp] + 1;
|
os << ' ' << verti + 1;
|
||||||
}
|
}
|
||||||
os << nl;
|
os << nl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,7 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
|
|||||||
|
|
||||||
fileName baseName = filename.lessExt();
|
fileName baseName = filename.lessExt();
|
||||||
|
|
||||||
// read cellTable names (if possible)
|
// Read cellTable names (if possible)
|
||||||
Map<word> cellTableLookup = readInpCellTable
|
Map<word> cellTableLookup = readInpCellTable
|
||||||
(
|
(
|
||||||
IFstream(starFileName(baseName, STARCDCore::INP_FILE))()
|
IFstream(starFileName(baseName, STARCDCore::INP_FILE))()
|
||||||
@ -111,7 +111,7 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
|
|||||||
pointId.clear();
|
pointId.clear();
|
||||||
|
|
||||||
|
|
||||||
// read .cel file
|
// Read .cel file
|
||||||
// ~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~
|
||||||
IFstream is(starFileName(baseName, STARCDCore::CEL_FILE));
|
IFstream is(starFileName(baseName, STARCDCore::CEL_FILE));
|
||||||
if (!is.good())
|
if (!is.good())
|
||||||
@ -131,7 +131,7 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
|
|||||||
|
|
||||||
// assume the cellTableIds are not intermixed
|
// assume the cellTableIds are not intermixed
|
||||||
bool sorted = true;
|
bool sorted = true;
|
||||||
label zoneI = 0;
|
label zoneId = 0;
|
||||||
|
|
||||||
label lineLabel, shapeId, nLabels, cellTableId, typeId;
|
label lineLabel, shapeId, nLabels, cellTableId, typeId;
|
||||||
DynamicList<label> vertexLabels(64);
|
DynamicList<label> vertexLabels(64);
|
||||||
@ -159,27 +159,27 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
|
|||||||
|
|
||||||
if (typeId == starcdShellType)
|
if (typeId == starcdShellType)
|
||||||
{
|
{
|
||||||
// Convert groupID into zoneID
|
// Convert cellTableId to zoneId
|
||||||
const auto fnd = lookup.cfind(cellTableId);
|
const auto iterGroup = lookup.cfind(cellTableId);
|
||||||
if (fnd.found())
|
if (iterGroup.found())
|
||||||
{
|
{
|
||||||
if (zoneI != fnd())
|
if (zoneId != *iterGroup)
|
||||||
{
|
{
|
||||||
// cellTableIds are intermixed
|
// cellTableIds are intermixed
|
||||||
sorted = false;
|
sorted = false;
|
||||||
}
|
}
|
||||||
zoneI = fnd();
|
zoneId = *iterGroup;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zoneI = dynSizes.size();
|
zoneId = dynSizes.size();
|
||||||
lookup.insert(cellTableId, zoneI);
|
lookup.insert(cellTableId, zoneId);
|
||||||
|
|
||||||
const auto tableNameIter = cellTableLookup.cfind(cellTableId);
|
const auto iterTableName = cellTableLookup.cfind(cellTableId);
|
||||||
|
|
||||||
if (tableNameIter.found())
|
if (iterTableName.found())
|
||||||
{
|
{
|
||||||
dynNames.append(tableNameIter());
|
dynNames.append(*iterTableName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -206,15 +206,15 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
|
|||||||
{
|
{
|
||||||
// a triangular 'face', convert to 'triFace' etc
|
// a triangular 'face', convert to 'triFace' etc
|
||||||
dynFaces.append(Face(tri));
|
dynFaces.append(Face(tri));
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynSizes[zoneI]++;
|
dynSizes[zoneId]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (nLabels >= 3)
|
||||||
{
|
{
|
||||||
dynFaces.append(Face(vertices));
|
dynFaces.append(Face(vertices));
|
||||||
dynZones.append(zoneI);
|
dynZones.append(zoneId);
|
||||||
dynSizes[zoneI]++;
|
dynSizes[zoneId]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,9 +262,9 @@ void Foam::fileFormats::STARCDsurfaceFormat<Face>::write
|
|||||||
writeHeader(os, STARCDCore::HEADER_CEL);
|
writeHeader(os, STARCDCore::HEADER_CEL);
|
||||||
|
|
||||||
label faceIndex = 0;
|
label faceIndex = 0;
|
||||||
forAll(zones, zoneI)
|
forAll(zones, zonei)
|
||||||
{
|
{
|
||||||
const surfZone& zone = zones[zoneI];
|
const surfZone& zone = zones[zonei];
|
||||||
const label nLocalFaces = zone.size();
|
const label nLocalFaces = zone.size();
|
||||||
|
|
||||||
if (useFaceMap)
|
if (useFaceMap)
|
||||||
@ -272,7 +272,7 @@ void Foam::fileFormats::STARCDsurfaceFormat<Face>::write
|
|||||||
for (label i=0; i<nLocalFaces; ++i)
|
for (label i=0; i<nLocalFaces; ++i)
|
||||||
{
|
{
|
||||||
const Face& f = faceLst[faceMap[faceIndex++]];
|
const Face& f = faceLst[faceMap[faceIndex++]];
|
||||||
writeShell(os, f, faceIndex, zoneI + 1);
|
writeShell(os, f, faceIndex, zonei + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -280,7 +280,7 @@ void Foam::fileFormats::STARCDsurfaceFormat<Face>::write
|
|||||||
for (label i=0; i<nLocalFaces; ++i)
|
for (label i=0; i<nLocalFaces; ++i)
|
||||||
{
|
{
|
||||||
const Face& f = faceLst[faceIndex++];
|
const Face& f = faceLst[faceIndex++];
|
||||||
writeShell(os, f, faceIndex, zoneI + 1);
|
writeShell(os, f, faceIndex, zonei + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -241,7 +241,7 @@ bool Foam::fileFormats::VTKsurfaceFormat<Face>::read
|
|||||||
|
|
||||||
this->sortFacesAndStore(dynFaces.xfer(), zones.xfer(), sorted);
|
this->sortFacesAndStore(dynFaces.xfer(), zones.xfer(), sorted);
|
||||||
|
|
||||||
// Add zones, retaining any empty ones
|
// Add zones (retaining empty ones)
|
||||||
this->addZones(zoneSizes, zoneNames);
|
this->addZones(zoneSizes, zoneNames);
|
||||||
}
|
}
|
||||||
this->addZonesToFaces(); // for labelledTri
|
this->addZonesToFaces(); // for labelledTri
|
||||||
|
|||||||
Reference in New Issue
Block a user