Files
OpenFOAM-6/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.C
Will Bainbridge db8751c521 AMI: Consistency between overlap/normalisation areas
The patch magSf calculation has been changed so that it uses the same
triangulation as the overlap algorithm. This improves consistency and
means that for exactly conforming patches (typically before any mesh
motion) the weights do not require normalisation.
2017-10-31 14:51:31 +00:00

409 lines
10 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "faceAreaIntersect.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
template<>
const char* NamedEnum<faceAreaIntersect::triangulationMode, 2>::names[] =
{
"fan",
"mesh"
};
}
const Foam::NamedEnum<Foam::faceAreaIntersect::triangulationMode, 2>
Foam::faceAreaIntersect::triangulationModeNames_;
Foam::scalar Foam::faceAreaIntersect::tol = 1e-6;
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
void Foam::faceAreaIntersect::triSliceWithPlane
(
const triPoints& tri,
const plane& p,
FixedList<triPoints, 10>& tris,
label& nTris,
const scalar len
)
{
// distance to cutting plane
FixedList<scalar, 3> d;
// determine how many of the points are above the cutting plane
label nCoPlanar = 0;
label nPos = 0;
label posI = -1;
label negI = -1;
label copI = -1;
forAll(tri, i)
{
d[i] = ((tri[i] - p.refPoint()) & p.normal());
if (mag(d[i]) < tol*len)
{
nCoPlanar++;
copI = i;
d[i] = 0.0;
}
else
{
if (d[i] > 0)
{
nPos++;
posI = i;
}
else
{
negI = i;
}
}
}
// Determine triangle area contribution
if
(
(nPos == 3)
|| ((nPos == 2) && (nCoPlanar == 1))
|| ((nPos == 1) && (nCoPlanar == 2))
)
{
/*
/\ _____
/ \ \ / /\
/____\ \ / / \
__________ ____v____ __/____\__
all points above cutting plane
- add complete triangle to list
*/
tris[nTris++] = tri;
}
else if ((nPos == 2) && (nCoPlanar == 0))
{
/*
i1________i2
\ /
--\----/--
\ /
\/
i0
2 points above plane, 1 below
- resulting quad above plane split into 2 triangles
- forget triangle below plane
*/
// point under the plane
label i0 = negI;
// indices of remaining points
label i1 = d.fcIndex(i0);
label i2 = d.fcIndex(i1);
// determine the two intersection points
point p01 = planeIntersection(d, tri, i0, i1);
point p02 = planeIntersection(d, tri, i0, i2);
// forget triangle below plane
// - decompose quad above plane into 2 triangles and add to list
setTriPoints(tri[i1], tri[i2], p02, nTris, tris);
setTriPoints(tri[i1], p02, p01, nTris, tris);
}
else if (nPos == 1)
{
// point above the plane
label i0 = posI;
if (nCoPlanar == 0)
{
/*
i0
/\
/ \
--/----\--
/______\
i2 i1
1 point above plane, 2 below
- keep triangle above intersection plane
- forget quad below plane
*/
// indices of remaining points
label i1 = d.fcIndex(i0);
label i2 = d.fcIndex(i1);
// determine the two intersection points
point p01 = planeIntersection(d, tri, i1, i0);
point p02 = planeIntersection(d, tri, i2, i0);
// add triangle above plane to list
setTriPoints(tri[i0], p01, p02, nTris, tris);
}
else
{
/*
i0
|\
| \
__|__\_i2_
| /
| /
|/
i1
1 point above plane, 1 on plane, 1 below
- keep triangle above intersection plane
*/
// point indices
label i1 = negI;
label i2 = copI;
// determine the intersection point
point p01 = planeIntersection(d, tri, i1, i0);
// add triangle above plane to list - clockwise points
if (d.fcIndex(i0) == i1)
{
setTriPoints(tri[i0], p01, tri[i2], nTris, tris);
}
else
{
setTriPoints(tri[i0], tri[i2], p01, nTris, tris);
}
}
}
else
{
/*
_________ __________ ___________
/\ \ /
/\ / \ \ /
/ \ /____\ \/
/____\
all points below cutting plane - forget
*/
}
}
Foam::scalar Foam::faceAreaIntersect::triangleIntersect
(
const triPoints& src,
const triPoints& tgt,
const vector& n
)
{
// Work storage
FixedList<triPoints, 10> workTris1;
label nWorkTris1 = 0;
FixedList<triPoints, 10> workTris2;
label nWorkTris2 = 0;
// cut source triangle with all inwards pointing faces of target triangle
// - triangles in workTris1 are inside target triangle
scalar t = sqrt(triArea(src));
// edge 0
{
// cut triangle src with plane and put resulting sub-triangles in
// workTris1 list
scalar s = mag(tgt[1] - tgt[0]);
plane pl0(tgt[0], tgt[1], tgt[1] + s*n);
triSliceWithPlane(src, pl0, workTris1, nWorkTris1, t);
}
if (nWorkTris1 == 0)
{
return 0.0;
}
// edge1
{
// cut workTris1 with plane and put resulting sub-triangles in
// workTris2 list (re-use tris storage)
scalar s = mag(tgt[2] - tgt[1]);
plane pl1(tgt[1], tgt[2], tgt[2] + s*n);
nWorkTris2 = 0;
for (label i = 0; i < nWorkTris1; i++)
{
triSliceWithPlane(workTris1[i], pl1, workTris2, nWorkTris2, t);
}
if (nWorkTris2 == 0)
{
return 0.0;
}
}
// edge2
{
// cut workTris2 with plane and put resulting sub-triangles in
// workTris1 list (re-use workTris1 storage)
scalar s = mag(tgt[2] - tgt[0]);
plane pl2(tgt[2], tgt[0], tgt[0] + s*n);
nWorkTris1 = 0;
for (label i = 0; i < nWorkTris2; i++)
{
triSliceWithPlane(workTris2[i], pl2, workTris1, nWorkTris1, t);
}
if (nWorkTris1 == 0)
{
return 0.0;
}
else
{
// calculate area of sub-triangles
scalar area = 0.0;
for (label i = 0; i < nWorkTris1; i++)
{
area += triArea(workTris1[i]);
}
return area;
}
}
}
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
Foam::faceAreaIntersect::faceAreaIntersect
(
const pointField& pointsA,
const pointField& pointsB,
const bool reverseB
)
:
pointsA_(pointsA),
pointsB_(pointsB),
reverseB_(reverseB)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::faceAreaIntersect::triangulate
(
const face& f,
const pointField& points,
const triangulationMode& triMode,
faceList& faceTris
)
{
faceTris.resize(f.nTriangles());
switch (triMode)
{
case tmFan:
{
for (label i = 0; i < f.nTriangles(); ++ i)
{
faceTris[i] = face(3);
faceTris[i][0] = f[0];
faceTris[i][1] = f[i + 1];
faceTris[i][2] = f[i + 2];
}
break;
}
case tmMesh:
{
const label nFaceTris = f.nTriangles();
label nFaceTris1 = 0;
const label nFaceTris2 = f.triangles(points, nFaceTris1, faceTris);
if (nFaceTris != nFaceTris1 || nFaceTris != nFaceTris2)
{
FatalErrorInFunction
<< "The numbers of reported triangles in the face do not "
<< "match that generated by the triangulation"
<< exit(FatalError);
}
}
}
}
Foam::scalar Foam::faceAreaIntersect::calc
(
const face& faceA,
const face& faceB,
const vector& n,
const triangulationMode& triMode
)
{
// split faces into triangles
faceList trisA, trisB;
triangulate(faceA, pointsA_, triMode, trisA);
triangulate(faceB, pointsB_, triMode, trisB);
// intersect triangles
scalar totalArea = 0.0;
forAll(trisA, tA)
{
triPoints tpA = getTriPoints(pointsA_, trisA[tA], false);
// if (triArea(tpA) > ROOTVSMALL)
{
forAll(trisB, tB)
{
triPoints tpB = getTriPoints(pointsB_, trisB[tB], !reverseB_);
// if (triArea(tpB) > ROOTVSMALL)
{
totalArea += triangleIntersect(tpA, tpB, n);
}
}
}
}
return totalArea;
}
// ************************************************************************* //