mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
- treat 'ofs' IO just like any other format - dropped BasicMeshedSurface, since MeshedSurface can now also have zero or more zones - UnsortedMeshedSurface is a special type of MeshedSurface with zero zones, but with additional zoneId labels - use MeshedSurfaceProxy for writing surfaces with points/faces/zones and optional faceMap - provides output interface for MeshedSurface, UnsortedMeshedSurface and surfMesh. - simplify output to filenames only, I can't see that the Ostream is needed anywhere - surfMesh renaming now works, after the objectRegistry fix
397 lines
12 KiB
C
397 lines
12 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 1991-2009 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 2 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, write to the Free Software Foundation,
|
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#include "NASsurfaceFormat.H"
|
|
#include "IFstream.H"
|
|
#include "IStringStream.H"
|
|
|
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
|
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
|
|
template<class Face>
|
|
Foam::fileFormats::NASsurfaceFormat<Face>::NASsurfaceFormat
|
|
(
|
|
const fileName& filename
|
|
)
|
|
{
|
|
read(filename);
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
template<class Face>
|
|
bool Foam::fileFormats::NASsurfaceFormat<Face>::read
|
|
(
|
|
const fileName& filename
|
|
)
|
|
{
|
|
const bool mustTriangulate = this->isTri();
|
|
this->clear();
|
|
|
|
IFstream is(filename);
|
|
if (!is.good())
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"fileFormats::NASsurfaceFormat::read(const fileName&)"
|
|
)
|
|
<< "Cannot read file " << filename
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
// Nastran index of points
|
|
DynamicList<label> pointId;
|
|
DynamicList<point> dynPoints;
|
|
DynamicList<Face> dynFaces;
|
|
DynamicList<label> dynZones;
|
|
DynamicList<label> dynSizes;
|
|
Map<label> lookup;
|
|
|
|
// assume the types are not intermixed
|
|
// leave faces that didn't have a group in 0
|
|
bool sorted = true;
|
|
label zoneI = 0;
|
|
|
|
// Name for face group
|
|
Map<word> nameLookup;
|
|
|
|
// Ansa tags. Denoted by $ANSA_NAME.
|
|
// These will appear just before the first use of a type.
|
|
// We read them and store the PSHELL types which are used to name
|
|
// the zones.
|
|
label ansaId = -1;
|
|
word ansaType, ansaName;
|
|
|
|
// A single warning per unrecognized command
|
|
HashSet<word> unhandledCmd;
|
|
|
|
while (is.good())
|
|
{
|
|
string line;
|
|
is.getLine(line);
|
|
|
|
// Ansa extension
|
|
if (line.substr(0, 10) == "$ANSA_NAME")
|
|
{
|
|
string::size_type sem0 = line.find (';', 0);
|
|
string::size_type sem1 = line.find (';', sem0+1);
|
|
string::size_type sem2 = line.find (';', sem1+1);
|
|
|
|
if
|
|
(
|
|
sem0 != string::npos
|
|
&& sem1 != string::npos
|
|
&& sem2 != string::npos
|
|
)
|
|
{
|
|
ansaId = readLabel
|
|
(
|
|
IStringStream(line.substr(sem0+1, sem1-sem0-1))()
|
|
);
|
|
ansaType = line.substr(sem1+1, sem2-sem1-1);
|
|
|
|
string rawName;
|
|
is.getLine(rawName);
|
|
if (rawName[rawName.size()-1] == '\r')
|
|
{
|
|
rawName = rawName.substr(1, rawName.size()-2);
|
|
}
|
|
else
|
|
{
|
|
rawName = rawName.substr(1, rawName.size()-1);
|
|
}
|
|
|
|
string::stripInvalid<word>(rawName);
|
|
ansaName = rawName;
|
|
|
|
// Info<< "ANSA tag for NastranID:" << ansaId
|
|
// << " of type " << ansaType
|
|
// << " name " << ansaName << endl;
|
|
}
|
|
}
|
|
|
|
|
|
// Hypermesh extension
|
|
// $HMNAME COMP 1"partName"
|
|
if
|
|
(
|
|
line.substr(0, 12) == "$HMNAME COMP"
|
|
&& line.find ('"') != string::npos
|
|
)
|
|
{
|
|
label groupId = readLabel
|
|
(
|
|
IStringStream(line.substr(16, 16))()
|
|
);
|
|
|
|
IStringStream lineStream(line.substr(32));
|
|
|
|
string rawName;
|
|
lineStream >> rawName;
|
|
string::stripInvalid<word>(rawName);
|
|
|
|
word groupName(rawName);
|
|
nameLookup.insert(groupId, groupName);
|
|
|
|
// Info<< "group " << groupId << " => " << groupName << endl;
|
|
}
|
|
|
|
|
|
// Skip empty or comment
|
|
if (line.empty() || line[0] == '$')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check if character 72 is continuation
|
|
if (line.size() > 72 && line[72] == '+')
|
|
{
|
|
line = line.substr(0, 72);
|
|
|
|
while (true)
|
|
{
|
|
string buf;
|
|
is.getLine(buf);
|
|
|
|
if (buf.size() > 72 && buf[72] == '+')
|
|
{
|
|
line += buf.substr(8, 64);
|
|
}
|
|
else
|
|
{
|
|
line += buf.substr(8, buf.size()-8);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Read first word
|
|
IStringStream lineStream(line);
|
|
word cmd;
|
|
lineStream >> cmd;
|
|
|
|
if (cmd == "CTRIA3")
|
|
{
|
|
triFace fTri;
|
|
|
|
label groupId = readLabel(IStringStream(line.substr(16,8))());
|
|
fTri[0] = readLabel(IStringStream(line.substr(24,8))());
|
|
fTri[1] = readLabel(IStringStream(line.substr(32,8))());
|
|
fTri[2] = readLabel(IStringStream(line.substr(40,8))());
|
|
|
|
// Convert groupID into zoneId
|
|
Map<label>::const_iterator fnd = lookup.find(groupId);
|
|
if (fnd != lookup.end())
|
|
{
|
|
if (zoneI != fnd())
|
|
{
|
|
// pshell types are intermixed
|
|
sorted = false;
|
|
}
|
|
zoneI = fnd();
|
|
}
|
|
else
|
|
{
|
|
zoneI = dynSizes.size();
|
|
lookup.insert(groupId, zoneI);
|
|
dynSizes.append(0);
|
|
// Info<< "zone" << zoneI << " => group " << groupId <<endl;
|
|
}
|
|
|
|
dynFaces.append(fTri);
|
|
dynZones.append(zoneI);
|
|
dynSizes[zoneI]++;
|
|
}
|
|
else if (cmd == "CQUAD4")
|
|
{
|
|
face fQuad(4);
|
|
UList<label>& f = static_cast<UList<label>&>(fQuad);
|
|
|
|
label groupId = readLabel(IStringStream(line.substr(16,8))());
|
|
fQuad[0] = readLabel(IStringStream(line.substr(24,8))());
|
|
fQuad[1] = readLabel(IStringStream(line.substr(32,8))());
|
|
fQuad[2] = readLabel(IStringStream(line.substr(40,8))());
|
|
fQuad[3] = readLabel(IStringStream(line.substr(48,8))());
|
|
|
|
// Convert groupID into zoneId
|
|
Map<label>::const_iterator fnd = lookup.find(groupId);
|
|
if (fnd != lookup.end())
|
|
{
|
|
if (zoneI != fnd())
|
|
{
|
|
// pshell types are intermixed
|
|
sorted = false;
|
|
}
|
|
zoneI = fnd();
|
|
}
|
|
else
|
|
{
|
|
zoneI = dynSizes.size();
|
|
lookup.insert(groupId, zoneI);
|
|
dynSizes.append(0);
|
|
// Info<< "zone" << zoneI << " => group " << groupId <<endl;
|
|
}
|
|
|
|
|
|
if (mustTriangulate)
|
|
{
|
|
dynFaces.append(triFace(f[0], f[1], f[2]));
|
|
dynFaces.append(triFace(f[0], f[2], f[3]));
|
|
dynZones.append(zoneI);
|
|
dynZones.append(zoneI);
|
|
dynSizes[zoneI] += 2;
|
|
}
|
|
else
|
|
{
|
|
dynFaces.append(Face(f));
|
|
dynZones.append(zoneI);
|
|
dynSizes[zoneI]++;
|
|
}
|
|
}
|
|
else if (cmd == "GRID")
|
|
{
|
|
label index = readLabel(IStringStream(line.substr(8,8))());
|
|
scalar x = parseNASCoord(line.substr(24, 8));
|
|
scalar y = parseNASCoord(line.substr(32, 8));
|
|
scalar z = parseNASCoord(line.substr(40, 8));
|
|
|
|
pointId.append(index);
|
|
dynPoints.append(point(x, y, z));
|
|
}
|
|
else if (cmd == "GRID*")
|
|
{
|
|
// Long format is on two lines with '*' continuation symbol
|
|
// on start of second line.
|
|
// Typical line (spaces compacted)
|
|
// GRID* 126 0 -5.55999875E+02 -5.68730474E+02
|
|
// * 2.14897901E+02
|
|
|
|
label index = readLabel(IStringStream(line.substr(8,16))());
|
|
scalar x = parseNASCoord(line.substr(40, 16));
|
|
scalar y = parseNASCoord(line.substr(56, 16));
|
|
|
|
is.getLine(line);
|
|
if (line[0] != '*')
|
|
{
|
|
FatalErrorIn
|
|
(
|
|
"fileFormats::NASsurfaceFormat::read(const fileName&)"
|
|
)
|
|
<< "Expected continuation symbol '*' when reading GRID*"
|
|
<< " (double precision coordinate) format" << nl
|
|
<< "Read:" << line << nl
|
|
<< "File:" << is.name() << " line:" << is.lineNumber()
|
|
<< exit(FatalError);
|
|
}
|
|
scalar z = parseNASCoord(line.substr(8, 16));
|
|
|
|
pointId.append(index);
|
|
dynPoints.append(point(x, y, z));
|
|
}
|
|
else if (cmd == "PSHELL")
|
|
{
|
|
// pshell type for zone names with the Ansa extension
|
|
label groupId = readLabel(IStringStream(line.substr(8,8))());
|
|
|
|
if (groupId == ansaId && ansaType == "PSHELL")
|
|
{
|
|
nameLookup.insert(ansaId, ansaName);
|
|
// Info<< "group " << groupId << " => " << ansaName << endl;
|
|
}
|
|
}
|
|
else if (unhandledCmd.insert(cmd))
|
|
{
|
|
Info<< "Unhandled Nastran command " << line << nl
|
|
<< "File:" << is.name() << " line:" << is.lineNumber()
|
|
<< endl;
|
|
}
|
|
}
|
|
|
|
// Info<< "Read faces:" << dynFaces.size()
|
|
// << " points:" << dynPoints.size()
|
|
// << endl;
|
|
|
|
// transfer to normal lists
|
|
this->storedPoints().transfer(dynPoints);
|
|
|
|
pointId.shrink();
|
|
dynFaces.shrink();
|
|
|
|
// Build inverse mapping (NASTRAN pointId -> index)
|
|
Map<label> mapPointId(2*pointId.size());
|
|
forAll(pointId, i)
|
|
{
|
|
mapPointId.insert(pointId[i], i);
|
|
}
|
|
|
|
// Relabel faces
|
|
// ~~~~~~~~~~~~~
|
|
forAll(dynFaces, i)
|
|
{
|
|
Face& f = dynFaces[i];
|
|
forAll(f, fp)
|
|
{
|
|
f[fp] = mapPointId[f[fp]];
|
|
}
|
|
}
|
|
pointId.clearStorage();
|
|
mapPointId.clear();
|
|
|
|
|
|
// create default zone names, or from ANSA/Hypermesh information
|
|
List<word> names(dynSizes.size());
|
|
forAllConstIter(Map<label>, lookup, iter)
|
|
{
|
|
const label zoneI = iter();
|
|
const label groupI = iter.key();
|
|
|
|
Map<word>::const_iterator fnd = nameLookup.find(groupI);
|
|
if (fnd != nameLookup.end())
|
|
{
|
|
names[zoneI] = fnd();
|
|
}
|
|
else
|
|
{
|
|
names[zoneI] = word("zone") + ::Foam::name(zoneI);
|
|
}
|
|
}
|
|
|
|
sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
|
|
|
|
// add zones, culling empty ones
|
|
this->addZones(dynSizes, names, true);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ************************************************************************* //
|