-
Mark OLESEN authored
- eliminates a potentially invalid code branch. Since it essentially had the same internals as std::swap anyhow, make that more evident. ENH: use std::swap for basic types - makes it clearer that they do not rely on any special semantics
Mark OLESEN authored- eliminates a potentially invalid code branch. Since it essentially had the same internals as std::swap anyhow, make that more evident. ENH: use std::swap for basic types - makes it clearer that they do not rely on any special semantics
cutTemplates.C 7.34 KiB
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "cut.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class AboveOp, class BelowOp>
typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::triCut
(
const FixedList<point, 3>& tri,
const FixedList<scalar, 3>& level,
const AboveOp& aboveOp,
const BelowOp& belowOp
)
{
// If everything is positive or negative, then process the triangle as a
// whole, and do a quick return
if (level[0] >= 0 && level[1] >= 0 && level[2] >= 0)
{
return aboveOp(tri) + belowOp();
}
if (level[0] <= 0 && level[1] <= 0 && level[2] <= 0)
{
return aboveOp() + belowOp(tri);
}
// There will be just one edge without a sign change. Find it, and put it
// opposite the first vertex. This may change the sign of the tri.
FixedList<label, 3> indices({0, 1, 2});
label i;
for (i = 0; i < 3; ++i)
{
if (level[(i + 1)%3]*level[(i + 2)%3] >= 0)
{
std::swap(indices[0], indices[i]);
break;
}
}
if (i == 3)
{
FatalErrorInFunction
<< "The number of tri vertices above the level set should always "
<< "be 1" << exit(FatalError);
}
// Correct the sign
if (indices[0] != 0)
{
std::swap(indices[1], indices[2]);
}
// Permute the data
const FixedList<point, 3> p = triReorder(tri, indices);
const FixedList<scalar, 3> l = triReorder(level, indices);
AboveOp a = triReorder(aboveOp, indices);
BelowOp b = triReorder(belowOp, indices);
// Slice off one corner to form a tri and a quad
Pair<scalar> f;
for (label i = 0; i < 2; ++i)
{
f[i] = l[0]/(l[0] - l[i+1]);
}
if (l[0] > 0)
{
return triCutTri(a, p, f) + triCutQuad(b, p, f);
}
else
{
return triCutQuad(a, p, f) + triCutTri(b, p, f);
}
}
template<class AboveOp, class BelowOp>
typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::triCut
(
const FixedList<point, 3>& tri,
const plane& pln,
const AboveOp& aboveOp,
const BelowOp& belowOp
)
{
// Set the level set to the signed distance from the plane
FixedList<scalar, 3> level;
for (label i = 0; i < 3; ++i)
{
level[i] = pln.signedDistance(tri[i]);
}
// Run the level set function
return triCut(tri, level, aboveOp, belowOp);
}
template<class AboveOp, class BelowOp>
typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::tetCut
(
const FixedList<point, 4>& tet,
const FixedList<scalar, 4>& level,
const AboveOp& aboveOp,
const BelowOp& belowOp
)
{
// Get the min and max over all four vertices and quick return if there is
// no change of sign
scalar levelMin = VGREAT, levelMax = - VGREAT;
for (label i = 0; i < 4; ++i)
{
levelMin = min(levelMin, level[i]);
levelMax = max(levelMax, level[i]);
}
if (levelMin >= 0)
{
return aboveOp(tet) + belowOp();
}
if (levelMax <= 0)
{
return aboveOp() + belowOp(tet);
}
// Partition the level so that positive values are at the start. This is
// like a single iteration of quick-sort, except that the pivot is a hard-
// coded zero, rather than an element of the array. This can change the sign
// of the tet.
FixedList<label, 4> indices({0, 1, 2, 3});
bool signChange = false;
label i = 0, j = 3;
while (true)
{
while (i < j && level[indices[i]] > 0)
{
i ++;
}
while (j > i && level[indices[j]] <= 0)
{
j --;
}
if (i == j)
{
break;
}
std::swap(indices[i], indices[j]);
signChange = !signChange;
}
// The number of vertices above the slice
label n = i;
// If there are more positives than negatives then reverse the order so that
// the negatives are at the start
if (n > 2)
{
n = 4 - n;
for (label i = 0; i < 2; ++i)
{
std::swap(indices[i], indices[3-i]);
}
}
// Correct the sign
if (signChange)
{
std::swap(indices[2], indices[3]);
}
// Permute the data
const FixedList<point, 4> p = tetReorder(tet, indices);
const FixedList<scalar, 4> l = tetReorder(level, indices);
AboveOp a = tetReorder(aboveOp, indices);
BelowOp b = tetReorder(belowOp, indices);
// Calculate the integrals above and below the level set
if (n == 1)
{
// Slice off one corner to form a tet and a prism
FixedList<scalar, 3> f;
for (label i = 0; i < 3; ++i)
{
f[i] = l[0]/(l[0] - l[i+1]);
}
if (l[0] > 0)
{
return tetCutTet(a, p, f) + tetCutPrism0(b, p, f);
}
else
{
return tetCutPrism0(a, p, f) + tetCutTet(b, p, f);
}
}
else if (n == 2)
{
// Slice off two corners to form two prisms
FixedList<scalar, 4> f;
for (label i = 0; i < 2; ++i)
{
for (label j = 0; j < 2; ++j)
{
f[2*i+j] = l[i]/(l[i] - l[j+2]);
}
}
if (l[0] > 0)
{
return tetCutPrism01(a, p, f) + tetCutPrism23(b, p, f);
}
else
{
return tetCutPrism23(a, p, f) + tetCutPrism01(b, p, f);
}
}
FatalErrorInFunction
<< "The number of tet vertices above the level set should always be "
<< "either 1 or 2" << exit(FatalError);
return aboveOp() + belowOp();
}
template<class AboveOp, class BelowOp>
typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::tetCut
(
const FixedList<point, 4>& tet,
const plane& pln,
const AboveOp& aboveOp,
const BelowOp& belowOp
)
{
// Set the level set to the signed distance from the plane
FixedList<scalar, 4> level;
for (label i = 0; i < 4; ++i)
{
level[i] = pln.signedDistance(tet[i]);
}
// Run the level set function
return tetCut(tet, level, aboveOp, belowOp);
}
// ************************************************************************* //