2010-05-12 13:27:55 +00:00
|
|
|
/*---------------------------------------------------------------------------*\
|
|
|
|
========= |
|
2013-12-11 16:09:41 +00:00
|
|
|
\\ / F ield | foam-extend: Open Source CFD
|
2015-05-17 13:32:07 +00:00
|
|
|
\\ / O peration | Version: 3.2
|
|
|
|
\\ / A nd | Web: http://www.foam-extend.org
|
|
|
|
\\/ M anipulation | For copyright notice see file Copyright
|
2010-05-12 13:27:55 +00:00
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
License
|
2013-12-11 16:09:41 +00:00
|
|
|
This file is part of foam-extend.
|
2010-05-12 13:27:55 +00:00
|
|
|
|
2013-12-11 16:09:41 +00:00
|
|
|
foam-extend is free software: you can redistribute it and/or modify it
|
2010-05-12 13:27:55 +00:00
|
|
|
under the terms of the GNU General Public License as published by the
|
2013-12-11 16:09:41 +00:00
|
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
2010-05-12 13:27:55 +00:00
|
|
|
option) any later version.
|
|
|
|
|
2013-12-11 16:09:41 +00:00
|
|
|
foam-extend 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.
|
2010-05-12 13:27:55 +00:00
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2013-12-11 16:09:41 +00:00
|
|
|
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
|
2010-05-12 13:27:55 +00:00
|
|
|
|
|
|
|
Description
|
|
|
|
Construct a cell shape from face information
|
|
|
|
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
#include "cellShapeRecognition.H"
|
|
|
|
#include "labelList.H"
|
|
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
|
|
|
|
namespace Foam
|
|
|
|
{
|
|
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
|
|
|
|
cellShape create3DCellShape
|
|
|
|
(
|
|
|
|
const label cellIndex,
|
|
|
|
const labelList& faceLabels,
|
|
|
|
const faceList& faces,
|
|
|
|
const labelList& owner,
|
|
|
|
const labelList& neighbour,
|
|
|
|
const label fluentCellModelID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// List of pointers to shape models for 3-D shape recognition
|
|
|
|
static List<const cellModel*> fluentCellModelLookup
|
|
|
|
(
|
|
|
|
7,
|
2010-08-25 21:42:57 +00:00
|
|
|
reinterpret_cast<const cellModel*>(0)
|
2010-05-12 13:27:55 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
fluentCellModelLookup[2] = cellModeller::lookup("tet");
|
|
|
|
fluentCellModelLookup[4] = cellModeller::lookup("hex");
|
|
|
|
fluentCellModelLookup[5] = cellModeller::lookup("pyr");
|
|
|
|
fluentCellModelLookup[6] = cellModeller::lookup("prism");
|
|
|
|
|
|
|
|
static label faceMatchingOrder[7][6] =
|
|
|
|
{
|
|
|
|
{-1, -1, -1, -1, -1, -1},
|
|
|
|
{-1, -1, -1, -1, -1, -1},
|
|
|
|
{ 0, 1, 2, 3, -1, -1}, // tet
|
|
|
|
{-1, -1, -1, -1, -1, -1},
|
|
|
|
{ 0, 2, 4, 3, 5, 1}, // hex
|
|
|
|
{ 0, 1, 2, 3, 4, -1}, // pyr
|
|
|
|
{ 0, 2, 3, 4, 1, -1}, // prism
|
|
|
|
};
|
|
|
|
|
|
|
|
const cellModel& curModel = *fluentCellModelLookup[fluentCellModelID];
|
|
|
|
|
|
|
|
// Checking
|
|
|
|
if (faceLabels.size() != curModel.nFaces())
|
|
|
|
{
|
|
|
|
FatalErrorIn
|
|
|
|
(
|
|
|
|
"create3DCellShape(const label cellIndex, "
|
|
|
|
"const labelList& faceLabels, const labelListList& faces, "
|
|
|
|
"const labelList& owner, const labelList& neighbour, "
|
|
|
|
"const label fluentCellModelID)"
|
|
|
|
) << "Number of face labels not equal to"
|
|
|
|
<< "number of face in the model. "
|
|
|
|
<< "Number of face labels: " << faceLabels.size()
|
|
|
|
<< " number of faces in model: " << curModel.nFaces()
|
|
|
|
<< abort(FatalError);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make a list of outward-pointing faces
|
|
|
|
labelListList localFaces(faceLabels.size());
|
|
|
|
|
|
|
|
forAll (faceLabels, faceI)
|
|
|
|
{
|
|
|
|
const label curFaceLabel = faceLabels[faceI];
|
|
|
|
|
|
|
|
const labelList& curFace = faces[curFaceLabel];
|
|
|
|
|
|
|
|
if (owner[curFaceLabel] == cellIndex)
|
|
|
|
{
|
|
|
|
localFaces[faceI] = curFace;
|
|
|
|
}
|
|
|
|
else if (neighbour[curFaceLabel] == cellIndex)
|
|
|
|
{
|
|
|
|
// Reverse the face
|
|
|
|
localFaces[faceI].setSize(curFace.size());
|
|
|
|
|
|
|
|
forAllReverse(curFace, i)
|
|
|
|
{
|
|
|
|
localFaces[faceI][curFace.size() - i - 1] =
|
|
|
|
curFace[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FatalErrorIn
|
|
|
|
(
|
|
|
|
"create3DCellShape(const label cellIndex, "
|
|
|
|
"const labelList& faceLabels, const labelListList& faces, "
|
|
|
|
"const labelList& owner, const labelList& neighbour, "
|
|
|
|
"const label fluentCellModelID)"
|
|
|
|
) << "face " << curFaceLabel
|
|
|
|
<< " does not belong to cell " << cellIndex
|
|
|
|
<< ". Face owner: " << owner[curFaceLabel] << " neighbour: "
|
|
|
|
<< neighbour[curFaceLabel]
|
|
|
|
<< abort(FatalError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Algorithm:
|
|
|
|
// Make an empty list of pointLabels and initialise it with -1. Pick the
|
|
|
|
// first face from modelFaces and look through the faces to find one with
|
|
|
|
// the same number of labels. Insert face by copying its labels into
|
|
|
|
// pointLabels. Mark the face as used. Loop through all model faces.
|
|
|
|
// For each model face loop through faces. If the face is unused and the
|
|
|
|
// numbers of labels fit, try to match the face onto the point labels. If
|
|
|
|
// at least one edge is matched, insert the face into pointLabels. If at
|
|
|
|
// any stage the matching algorithm reaches the end of faces, the matching
|
|
|
|
// algorithm has failed. Once all the faces are matched, the list of
|
|
|
|
// pointLabels defines the model.
|
|
|
|
|
|
|
|
// Make a list of empty pointLabels
|
|
|
|
labelList pointLabels(curModel.nPoints(), -1);
|
|
|
|
|
|
|
|
// Follow the used mesh faces
|
|
|
|
List<bool> meshFaceUsed(localFaces.size(), false);
|
|
|
|
|
|
|
|
// Get the raw model faces
|
|
|
|
const faceList& modelFaces = curModel.modelFaces();
|
|
|
|
|
|
|
|
// Insert the first face into the list
|
|
|
|
const labelList& firstModelFace =
|
|
|
|
modelFaces[faceMatchingOrder[fluentCellModelID][0]];
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
forAll (localFaces, meshFaceI)
|
|
|
|
{
|
|
|
|
if (localFaces[meshFaceI].size() == firstModelFace.size())
|
|
|
|
{
|
|
|
|
// Match. Insert points into the pointLabels
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
const labelList& curMeshFace = localFaces[meshFaceI];
|
|
|
|
|
|
|
|
meshFaceUsed[meshFaceI] = true;
|
|
|
|
|
|
|
|
forAll (curMeshFace, pointI)
|
|
|
|
{
|
|
|
|
pointLabels[firstModelFace[pointI]] = curMeshFace[pointI];
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
FatalErrorIn
|
|
|
|
(
|
|
|
|
"create3DCellShape(const label cellIndex, "
|
|
|
|
"const labelList& faceLabels, const labelListList& faces, "
|
|
|
|
"const labelList& owner, const labelList& neighbour, "
|
|
|
|
"const label fluentCellModelID)"
|
|
|
|
) << "Cannot find match for first face. "
|
|
|
|
<< "cell model: " << curModel.name() << " first model face: "
|
|
|
|
<< firstModelFace << " Mesh faces: " << localFaces
|
|
|
|
<< abort(FatalError);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (label modelFaceI = 1; modelFaceI < modelFaces.size(); modelFaceI++)
|
|
|
|
{
|
|
|
|
// get the next model face
|
|
|
|
const labelList& curModelFace =
|
|
|
|
modelFaces
|
|
|
|
[faceMatchingOrder[fluentCellModelID][modelFaceI]];
|
|
|
|
|
|
|
|
found = false;
|
|
|
|
|
|
|
|
// Loop through mesh faces until a match is found
|
|
|
|
forAll (localFaces, meshFaceI)
|
|
|
|
{
|
|
|
|
if
|
|
|
|
(
|
|
|
|
!meshFaceUsed[meshFaceI]
|
|
|
|
&& localFaces[meshFaceI].size() == curModelFace.size()
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// A possible match. A mesh face will be rotated, so make a copy
|
|
|
|
labelList meshFaceLabels = localFaces[meshFaceI];
|
|
|
|
|
|
|
|
for
|
|
|
|
(
|
|
|
|
label rotation = 0;
|
|
|
|
rotation < meshFaceLabels.size();
|
|
|
|
rotation++
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// try matching the face
|
|
|
|
label nMatchedLabels = 0;
|
|
|
|
|
|
|
|
forAll (meshFaceLabels, pointI)
|
|
|
|
{
|
|
|
|
if
|
|
|
|
(
|
|
|
|
pointLabels[curModelFace[pointI]]
|
|
|
|
== meshFaceLabels[pointI]
|
|
|
|
)
|
|
|
|
{
|
|
|
|
nMatchedLabels++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nMatchedLabels >= 2)
|
|
|
|
{
|
|
|
|
// match!
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
// match found. Insert mesh face
|
|
|
|
forAll (meshFaceLabels, pointI)
|
|
|
|
{
|
|
|
|
pointLabels[curModelFace[pointI]] =
|
|
|
|
meshFaceLabels[pointI];
|
|
|
|
}
|
|
|
|
|
|
|
|
meshFaceUsed[meshFaceI] = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// No match found. Rotate face
|
|
|
|
label firstLabel = meshFaceLabels[0];
|
|
|
|
|
|
|
|
for (label i = 1; i < meshFaceLabels.size(); i++)
|
|
|
|
{
|
|
|
|
meshFaceLabels[i - 1] = meshFaceLabels[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
meshFaceLabels[meshFaceLabels.size() - 1] = firstLabel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
// A model face is not matched. Shape detection failed
|
|
|
|
FatalErrorIn
|
|
|
|
(
|
|
|
|
"create3DCellShape(const label cellIndex, "
|
|
|
|
"const labelList& faceLabels, const labelListList& faces, "
|
|
|
|
"const labelList& owner, const labelList& neighbour, "
|
|
|
|
"const label fluentCellModelID)"
|
|
|
|
) << "Cannot find match for face "
|
|
|
|
<< modelFaceI
|
|
|
|
<< ".\nModel: " << curModel.name() << " model face: "
|
|
|
|
<< curModelFace << " Mesh faces: " << localFaces
|
|
|
|
<< "Matched points: " << pointLabels
|
|
|
|
<< abort(FatalError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cellShape(curModel, pointLabels);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
|
|
|
|
} // End namespace Foam
|
|
|
|
|
|
|
|
// ************************************************************************* //
|