From 5edba1d109d377a5d675e836211890550aca268f Mon Sep 17 00:00:00 2001 From: sergio <sergio> Date: Tue, 10 Jan 2012 15:38:07 +0000 Subject: [PATCH] ENH: Adding mapRegion option to meshToMesh and volume weighted interpolation method --- src/sampling/Make/files | 4 + .../meshToMesh/calculateMeshToMeshWeights.C | 123 ++ .../meshToMesh/meshToMesh.C | 10 +- .../meshToMesh/meshToMesh.H | 29 +- .../meshToMesh/meshToMeshInterpolate.C | 68 +- .../tetOverlapVolume/tetOverlapVolume.C | 795 +++++++++++++ .../tetOverlapVolume/tetOverlapVolume.H | 218 ++++ .../tetOverlapVolume/tetPoints.H | 114 ++ .../tetOverlapVolume/tetrahedron.C | 341 ++++++ .../tetOverlapVolume/tetrahedron.H | 315 +++++ .../tetOverlapVolume/tetrahedronI.H | 1012 +++++++++++++++++ 11 files changed, 3020 insertions(+), 9 deletions(-) create mode 100644 src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.C create mode 100644 src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.H create mode 100644 src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetPoints.H create mode 100644 src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.C create mode 100644 src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.H create mode 100644 src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedronI.H diff --git a/src/sampling/Make/files b/src/sampling/Make/files index 0c89693a8ea..17099071a57 100644 --- a/src/sampling/Make/files +++ b/src/sampling/Make/files @@ -69,4 +69,8 @@ $(meshToMesh)/meshToMesh.C $(meshToMesh)/calculateMeshToMeshAddressing.C $(meshToMesh)/calculateMeshToMeshWeights.C +tetOverlapVolume = meshToMeshInterpolation/tetOverlapVolume +$(tetOverlapVolume)/tetOverlapVolume.C + + LIB = $(FOAM_LIBBIN)/libsampling diff --git a/src/sampling/meshToMeshInterpolation/meshToMesh/calculateMeshToMeshWeights.C b/src/sampling/meshToMeshInterpolation/meshToMesh/calculateMeshToMeshWeights.C index 532fee3f85c..c3db6586ad5 100644 --- a/src/sampling/meshToMeshInterpolation/meshToMesh/calculateMeshToMeshWeights.C +++ b/src/sampling/meshToMeshInterpolation/meshToMesh/calculateMeshToMeshWeights.C @@ -24,6 +24,7 @@ License \*---------------------------------------------------------------------------*/ #include "meshToMesh.H" +#include "tetOverlapVolume.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // @@ -99,6 +100,108 @@ void Foam::meshToMesh::calculateInverseDistanceWeights() const } +void Foam::meshToMesh::calculateInverseVolumeWeights() const +{ + if (debug) + { + Info<< "meshToMesh::calculateInverseVolumeWeights() : " + << "calculating inverse volume weighting factors" << endl; + } + + if (inverseVolumeWeightsPtr_) + { + FatalErrorIn("meshToMesh::calculateInverseVolumeWeights()") + << "weighting factors already calculated" + << exit(FatalError); + } + + inverseVolumeWeightsPtr_ = new scalarListList(toMesh_.nCells()); + scalarListList& invVolCoeffs = *inverseVolumeWeightsPtr_; + + labelListList& cellToCell = *cellToCellAddressingPtr_; + + tetOverlapVolume overlapEngine; + + forAll(cellToCell, celli) + { + const labelList& overlapCells = cellToCell[celli]; + + if (overlapCells.size() > 0) + { + invVolCoeffs[celli].setSize(overlapCells.size()); + scalar v(0); + forAll (overlapCells, j) + { + label cellFrom = overlapCells[j]; + treeBoundBox bbFromMesh + ( + pointField + ( + fromMesh_.points(), + fromMesh_.cellPoints()[cellFrom] + ) + ); + + v = overlapEngine.cellCellOverlapVolumeMinDecomp + ( + toMesh_, + celli, + + fromMesh_, + cellFrom, + bbFromMesh + ); + invVolCoeffs[celli][j] = v/toMesh_.V()[celli]; + } + if (celli == 2) + { + Info << "cellToCell :" << cellToCell[celli] << endl; + Info << "invVolCoeffs :" << invVolCoeffs[celli] << endl; + } + } + } +} + + +void Foam::meshToMesh::calculateCellToCellAddressing() const +{ + if (debug) + { + Info<< "meshToMesh::calculateCellToCellAddressing() : " + << "calculating cell to cell addressing" << endl; + } + + if (cellToCellAddressingPtr_) + { + FatalErrorIn("meshToMesh::calculateCellToCellAddressing()") + << "addressing already calculated" + << exit(FatalError); + } + + tetOverlapVolume overlapEngine; + + cellToCellAddressingPtr_ = new labelListList(toMesh_.nCells()); + labelListList& cellToCell = *cellToCellAddressingPtr_; + + + forAll(cellToCell, iTo) + { + const labelList overLapCells = + overlapEngine.overlappingCells(fromMesh_, toMesh_, iTo); + if (overLapCells.size() > 0) + { + //Info << "To " << iTo << endl; + //Info << "cellToCell " << overLapCells << endl; + + cellToCell[iTo].setSize(overLapCells.size()); + forAll(overLapCells, j) + { + cellToCell[iTo][j] = overLapCells[j]; + } + } + } +} + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // const Foam::scalarListList& Foam::meshToMesh::inverseDistanceWeights() const @@ -112,4 +215,24 @@ const Foam::scalarListList& Foam::meshToMesh::inverseDistanceWeights() const } +const Foam::scalarListList& Foam::meshToMesh::inverseVolumeWeights() const +{ + if (!inverseVolumeWeightsPtr_) + { + calculateInverseVolumeWeights(); + } + + return *inverseVolumeWeightsPtr_; +} + +const Foam::labelListList& Foam::meshToMesh::cellToCellAddressing() const +{ + if (!cellToCellAddressingPtr_) + { + calculateCellToCellAddressing(); + } + + return *cellToCellAddressingPtr_; +} + // ************************************************************************* // diff --git a/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.C b/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.C index c5f95879501..fa495c40ce5 100644 --- a/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.C +++ b/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.C @@ -48,7 +48,9 @@ Foam::meshToMesh::meshToMesh patchMap_(patchMap), cellAddressing_(toMesh_.nCells()), boundaryAddressing_(toMesh_.boundaryMesh().size()), - inverseDistanceWeightsPtr_(NULL) + inverseDistanceWeightsPtr_(NULL), + inverseVolumeWeightsPtr_(NULL), + cellToCellAddressingPtr_(NULL) { forAll(fromMesh_.boundaryMesh(), patchi) { @@ -118,7 +120,9 @@ Foam::meshToMesh::meshToMesh toMesh_(meshTo), cellAddressing_(toMesh_.nCells()), boundaryAddressing_(toMesh_.boundaryMesh().size()), - inverseDistanceWeightsPtr_(NULL) + inverseDistanceWeightsPtr_(NULL), + inverseVolumeWeightsPtr_(NULL), + cellToCellAddressingPtr_(NULL) { // check whether both meshes have got the same number // of boundary patches @@ -198,6 +202,8 @@ Foam::meshToMesh::meshToMesh Foam::meshToMesh::~meshToMesh() { deleteDemandDrivenData(inverseDistanceWeightsPtr_); + deleteDemandDrivenData(inverseVolumeWeightsPtr_); + deleteDemandDrivenData(cellToCellAddressingPtr_); } diff --git a/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.H b/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.H index 83d1ee902ac..e60871be259 100644 --- a/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.H +++ b/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMesh.H @@ -88,6 +88,12 @@ class meshToMesh //- Inverse-distance interpolation weights mutable scalarListList* inverseDistanceWeightsPtr_; + //- Inverse-volume interpolation weights + mutable scalarListList* inverseVolumeWeightsPtr_; + + //- Cell to cell overlap addressing + mutable labelListList* cellToCellAddressingPtr_; + // Private Member Functions @@ -104,8 +110,16 @@ class meshToMesh void calculateInverseDistanceWeights() const; + void calculateInverseVolumeWeights() const; + + void calculateCellToCellAddressing() const; + const scalarListList& inverseDistanceWeights() const; + const scalarListList& inverseVolumeWeights() const; + + const labelListList& cellToCellAddressing() const; + // Private static data members @@ -124,7 +138,8 @@ public: { MAP, INTERPOLATE, - CELL_POINT_INTERPOLATE + CELL_POINT_INTERPOLATE, + CELL_VOLUME_WEIGHT }; @@ -239,6 +254,18 @@ public: const CombineOp& cop ) const; + //- Interpolate field using inverse-volume weights + template<class Type, class CombineOp> + void interpolateField + ( + Field<Type>&, + const GeometricField<Type, fvPatchField, volMesh>&, + const labelListList& adr, + const scalarListList& weights, + const CombineOp& cop + ) const; + + //- Interpolate field using cell-point interpolation template<class Type, class CombineOp> void interpolateField diff --git a/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMeshInterpolate.C b/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMeshInterpolate.C index 7ed543ed3cd..372194e3225 100644 --- a/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMeshInterpolate.C +++ b/src/sampling/meshToMeshInterpolation/meshToMesh/meshToMeshInterpolate.C @@ -54,6 +54,33 @@ void Foam::meshToMesh::mapField } +template<class Type, class CombineOp> +void Foam::meshToMesh::interpolateField +( + Field<Type>& toF, + const GeometricField<Type, fvPatchField, volMesh>& fromVf, + const labelListList& adr, + const scalarListList& weights, + const CombineOp& cop +) const +{ + // Inverse volume weighted interpolation + forAll(toF, celli) + { + const labelList& overlapCells = adr[celli]; + const scalarList& w = weights[celli]; + + Type f = pTraits<Type>::zero; + forAll(overlapCells, i) + { + label fromCelli = overlapCells[i]; + f += fromVf[fromCelli]*w[i]; + cop(toF[celli], f); + } + } +} + + template<class Type, class CombineOp> void Foam::meshToMesh::interpolateField ( @@ -162,6 +189,7 @@ void Foam::meshToMesh::interpolateInternalField break; case INTERPOLATE: + { interpolateField ( toF, @@ -170,9 +198,10 @@ void Foam::meshToMesh::interpolateInternalField inverseDistanceWeights(), cop ); - break; - + break; + } case CELL_POINT_INTERPOLATE: + { interpolateField ( toF, @@ -181,8 +210,24 @@ void Foam::meshToMesh::interpolateInternalField toMesh_.cellCentres(), cop ); - break; + break; + } + case CELL_VOLUME_WEIGHT: + { + const labelListList& cellToCell = cellToCellAddressing(); + const scalarListList& invVolWeights = inverseVolumeWeights(); + + interpolateField + ( + toF, + fromVf, + cellToCell, + invVolWeights, + cop + ); + break; + } default: FatalErrorIn ( @@ -229,6 +274,7 @@ void Foam::meshToMesh::interpolate switch(ord) { case MAP: + { mapField ( toVf.boundaryField()[patchi], @@ -236,9 +282,11 @@ void Foam::meshToMesh::interpolate boundaryAddressing_[patchi], cop ); - break; + break; + } case INTERPOLATE: + { interpolateField ( toVf.boundaryField()[patchi], @@ -247,9 +295,11 @@ void Foam::meshToMesh::interpolate toPatch.Cf(), cop ); - break; + break; + } case CELL_POINT_INTERPOLATE: + { interpolateField ( toVf.boundaryField()[patchi], @@ -258,7 +308,13 @@ void Foam::meshToMesh::interpolate toPatch.Cf(), cop ); - break; + break; + } + case CELL_VOLUME_WEIGHT: + { + // Do nothing + break; + } default: FatalErrorIn diff --git a/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.C b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.C new file mode 100644 index 00000000000..d36730a0eea --- /dev/null +++ b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.C @@ -0,0 +1,795 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2011 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 "tetOverlapVolume.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +defineTypeNameAndDebug(Foam::tetOverlapVolume, 0); + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::tetOverlapVolume::tetOverlapVolume() +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::tetOverlapVolume::~tetOverlapVolume() +{} + + +// * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * * // + +Foam::point Foam::tetOverlapVolume::planeIntersection +( + const FixedList<scalar, 4>& d, + const tetPoints& t, + const label negI, + const label posI +) +{ + return (d[posI]*t[negI] - d[negI]*t[posI])/(-d[negI]+d[posI]); +} + + +template <class TetOp> +inline void Foam::tetOverlapVolume::decomposePrism +( + const FixedList<point, 6>& points, + TetOp& op +) +{ + op(tetPoints(points[1], points[3], points[2], points[0])); + op(tetPoints(points[1], points[2], points[3], points[4])); + op(tetPoints(points[4], points[2], points[3], points[5])); +} + + +template <class AboveTetOp, class BelowTetOp> +inline void Foam::tetOverlapVolume::tetSliceWithPlane +( + const tetPoints& tet, + const plane& pl, + + AboveTetOp& aboveOp, + BelowTetOp& belowOp +) +{ + // Distance to plane + FixedList<scalar, 4> d; + label nPos = 0; + forAll(tet, i) + { + d[i] = ((tet[i]-pl.refPoint()) & pl.normal()); + if (d[i] > 0) + { + nPos++; + } + } + + if (nPos == 4) + { + aboveOp(tet); + } + else if (nPos == 3) + { + // Sliced into below tet and above prism. Prism gets split into + // two tets. + + // Find the below tet + label i0 = -1; + forAll(d, i) + { + if (d[i] <= 0) + { + i0 = i; + break; + } + } + + label i1 = d.fcIndex(i0); + label i2 = d.fcIndex(i1); + label i3 = d.fcIndex(i2); + + point p01 = planeIntersection(d, tet, i0, i1); + point p02 = planeIntersection(d, tet, i0, i2); + point p03 = planeIntersection(d, tet, i0, i3); + + // i0 = tetCell vertex 0: p01,p02,p03 outwards pointing triad + // ,, 1 : ,, inwards pointing triad + // ,, 2 : ,, outwards pointing triad + // ,, 3 : ,, inwards pointing triad + + //Pout<< "Split 3pos tet " << tet << " d:" << d << " into" << nl; + + if (i0 == 0 || i0 == 2) + { + tetPoints t(tet[i0], p01, p02, p03); + //Pout<< " belowtet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 3, belowTet i0==0 or 2"); + belowOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i1]; + p[1] = tet[i3]; + p[2] = tet[i2]; + p[3] = p01; + p[4] = p03; + p[5] = p02; + //Pout<< " aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + else + { + tetPoints t(p01, p02, p03, tet[i0]); + //Pout<< " belowtet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 3, belowTet i0==1 or 3"); + belowOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i3]; + p[1] = tet[i1]; + p[2] = tet[i2]; + p[3] = p03; + p[4] = p01; + p[5] = p02; + //Pout<< " aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + } + else if (nPos == 2) + { + // Tet cut into two prisms. Determine the positive one. + label pos0 = -1; + label pos1 = -1; + label neg0 = -1; + label neg1 = -1; + forAll(d, i) + { + if (d[i] > 0) + { + if (pos0 == -1) + { + pos0 = i; + } + else + { + pos1 = i; + } + } + else + { + if (neg0 == -1) + { + neg0 = i; + } + else + { + neg1 = i; + } + } + } + + //Pout<< "Split 2pos tet " << tet << " d:" << d + // << " around pos0:" << pos0 << " pos1:" << pos1 + // << " neg0:" << neg0 << " neg1:" << neg1 << " into" << nl; + + const edge posEdge(pos0, pos1); + + if (posEdge == edge(0, 1)) + { + point p02 = planeIntersection(d, tet, 0, 2); + point p03 = planeIntersection(d, tet, 0, 3); + point p12 = planeIntersection(d, tet, 1, 2); + point p13 = planeIntersection(d, tet, 1, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[0]; + p[1] = p02; + p[2] = p03; + p[3] = tet[1]; + p[4] = p12; + p[5] = p13; + //Pout<< " 01 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p02; + p[2] = p12; + p[3] = tet[3]; + p[4] = p03; + p[5] = p13; + //Pout<< " 01 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(1, 2)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p13 = planeIntersection(d, tet, 1, 3); + point p02 = planeIntersection(d, tet, 0, 2); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[1]; + p[1] = p01; + p[2] = p13; + p[3] = tet[2]; + p[4] = p02; + p[5] = p23; + //Pout<< " 12 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[3]; + p[1] = p23; + p[2] = p13; + p[3] = tet[0]; + p[4] = p02; + p[5] = p01; + //Pout<< " 12 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(2, 0)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p03 = planeIntersection(d, tet, 0, 3); + point p12 = planeIntersection(d, tet, 1, 2); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p12; + p[2] = p23; + p[3] = tet[0]; + p[4] = p01; + p[5] = p03; + //Pout<< " 20 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[1]; + p[1] = p12; + p[2] = p01; + p[3] = tet[3]; + p[4] = p23; + p[5] = p03; + //Pout<< " 20 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(0, 3)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p02 = planeIntersection(d, tet, 0, 2); + point p13 = planeIntersection(d, tet, 1, 3); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[3]; + p[1] = p23; + p[2] = p13; + p[3] = tet[0]; + p[4] = p02; + p[5] = p01; + //Pout<< " 03 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p23; + p[2] = p02; + p[3] = tet[1]; + p[4] = p13; + p[5] = p01; + //Pout<< " 03 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(1, 3)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p12 = planeIntersection(d, tet, 1, 2); + point p03 = planeIntersection(d, tet, 0, 3); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[1]; + p[1] = p12; + p[2] = p01; + p[3] = tet[3]; + p[4] = p23; + p[5] = p03; + //Pout<< " 13 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p12; + p[2] = p23; + p[3] = tet[0]; + p[4] = p01; + p[5] = p03; + //Pout<< " 13 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(2, 3)) + { + point p02 = planeIntersection(d, tet, 0, 2); + point p12 = planeIntersection(d, tet, 1, 2); + point p03 = planeIntersection(d, tet, 0, 3); + point p13 = planeIntersection(d, tet, 1, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p02; + p[2] = p12; + p[3] = tet[3]; + p[4] = p03; + p[5] = p13; + //Pout<< " 23 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[0]; + p[1] = p02; + p[2] = p03; + p[3] = tet[1]; + p[4] = p12; + p[5] = p13; + //Pout<< " 23 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else + { + FatalErrorIn("tetSliceWithPlane(..)") << "Missed edge:" << posEdge + << abort(FatalError); + } + } + else if (nPos == 1) + { + // Find the positive tet + label i0 = -1; + forAll(d, i) + { + if (d[i] > 0) + { + i0 = i; + break; + } + } + + label i1 = d.fcIndex(i0); + label i2 = d.fcIndex(i1); + label i3 = d.fcIndex(i2); + + point p01 = planeIntersection(d, tet, i0, i1); + point p02 = planeIntersection(d, tet, i0, i2); + point p03 = planeIntersection(d, tet, i0, i3); + + //Pout<< "Split 1pos tet " << tet << " d:" << d << " into" << nl; + + if (i0 == 0 || i0 == 2) + { + tetPoints t(tet[i0], p01, p02, p03); + //Pout<< " abovetet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 1, aboveTets i0==0 or 2"); + aboveOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i1]; + p[1] = tet[i3]; + p[2] = tet[i2]; + p[3] = p01; + p[4] = p03; + p[5] = p02; + //Pout<< " belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + else + { + tetPoints t(p01, p02, p03, tet[i0]); + //Pout<< " abovetet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 1, aboveTets i0==1 or 3"); + aboveOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i3]; + p[1] = tet[i1]; + p[2] = tet[i2]; + p[3] = p03; + p[4] = p01; + p[5] = p02; + //Pout<< " belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else // nPos == 0 + { + belowOp(tet); + } +} + + +void Foam::tetOverlapVolume::tetTetOverlap +( + const tetPoints& tetA, + const tetPoints& tetB, + FixedList<tetPoints, 200>& insideTets, + label& nInside, + FixedList<tetPoints, 200>& outsideTets, + label& nOutside +) +{ + // Work storage + FixedList<tetPoints, 200> cutInsideTets; + label nCutInside = 0; + + storeTetOp inside(insideTets, nInside); + storeTetOp cutInside(cutInsideTets, nCutInside); + dummyTetOp outside; + + + + // Cut tetA with all inwards pointing faces of tetB. Any tets remaining + // in aboveTets are inside tetB. + + { + // face0 + plane pl0(tetB[1], tetB[3], tetB[2]); + + // Cut and insert subtets into cutInsideTets (either by getting + // an index from freeSlots or by appending to insideTets) or + // insert into outsideTets + tetSliceWithPlane(tetA, pl0, cutInside, outside); + } + + if (nCutInside == 0) + { + nInside = nCutInside; + return; + } + + { + // face1 + plane pl1(tetB[0], tetB[2], tetB[3]); + + nInside = 0; + + for (label i = 0; i < nCutInside; i++) + { + tetSliceWithPlane(cutInsideTets[i], pl1, inside, outside); + } + + if (nInside == 0) + { + return; + } + } + + { + // face2 + plane pl2(tetB[0], tetB[3], tetB[1]); + + nCutInside = 0; + + for (label i = 0; i < nInside; i++) + { + tetSliceWithPlane(insideTets[i], pl2, cutInside, outside); + } + + if (nCutInside == 0) + { + nInside = nCutInside; + return; + } + } + + { + // face3 + plane pl3(tetB[0], tetB[1], tetB[2]); + + nInside = 0; + + for (label i = 0; i < nCutInside; i++) + { + tetSliceWithPlane(cutInsideTets[i], pl3, inside, outside); + } + } +} + + +inline Foam::scalar +Foam::tetOverlapVolume::tetTetOverlapVol +( + const tetPoints& tetA, + const tetPoints& tetB +) +{ + FixedList<tetPoints, 200> insideTets; + label nInside = 0; + FixedList<tetPoints, 200> cutInsideTets; + label nCutInside = 0; + + storeTetOp inside(insideTets, nInside); + storeTetOp cutInside(cutInsideTets, nCutInside); + sumTetVolOp volInside; + dummyTetOp outside; + + // face0 + plane pl0(tetB[1], tetB[3], tetB[2]); + tetA.tet().sliceWithPlane(pl0, cutInside, outside); + if (nCutInside == 0) + { + return 0.0; + } + + // face1 + plane pl1(tetB[0], tetB[2], tetB[3]); + nInside = 0; + for (label i = 0; i < nCutInside; i++) + { + const tetPointRef t = cutInsideTets[i].tet(); + t.sliceWithPlane(pl1, inside, outside); + } + if (nInside == 0) + { + return 0.0; + } + + // face2 + plane pl2(tetB[0], tetB[3], tetB[1]); + nCutInside = 0; + for (label i = 0; i < nInside; i++) + { + const tetPointRef t = insideTets[i].tet(); + t.sliceWithPlane(pl2, cutInside, outside); + } + if (nCutInside == 0) + { + return 0.0; + } + + // face3 + plane pl3(tetB[0], tetB[1], tetB[2]); + for (label i = 0; i < nCutInside; i++) + { + const tetPointRef t = cutInsideTets[i].tet(); + t.sliceWithPlane(pl3, volInside, outside); + } + + return volInside.vol_; +} + + +inline const Foam::treeBoundBox Foam::tetOverlapVolume::pyrBb +( + const pointField& points, + const face& f, + const point& fc +) +{ + treeBoundBox bb(fc, fc); + forAll(f, fp) + { + const point& pt = points[f[fp]]; + bb.min() = min(bb.min(), pt); + bb.max() = max(bb.max(), pt); + } + return bb; +} + + +// * * * * * * * * * * * Public Member Functions * * * * * * * * * * * * * // + +Foam::scalar Foam::tetOverlapVolume::cellCellOverlapVolumeMinDecomp +( + const primitiveMesh& meshA, + const label cellAI, + + const primitiveMesh& meshB, + const label cellBI, + const treeBoundBox& cellBbB +) +{ + const cell& cFacesA = meshA.cells()[cellAI]; + const point& ccA = meshA.cellCentres()[cellAI]; + + const cell& cFacesB = meshB.cells()[cellBI]; + const point& ccB = meshB.cellCentres()[cellBI]; + + scalar vol = 0.0; + + forAll(cFacesA, cFA) + { + label faceAI = cFacesA[cFA]; + + const face& fA = meshA.faces()[faceAI]; + const treeBoundBox pyrA = pyrBb(meshA.points(), fA, ccA); + if (!pyrA.overlaps(cellBbB)) + { + continue; + } + + bool ownA = (meshA.faceOwner()[faceAI] == cellAI); + + label tetBasePtAI = 0; + + const point& tetBasePtA = meshA.points()[fA[tetBasePtAI]]; + + for (label tetPtI = 1; tetPtI < fA.size() - 1; tetPtI++) + { + label facePtAI = (tetPtI + tetBasePtAI) % fA.size(); + label otherFacePtAI = fA.fcIndex(facePtAI); + + label pt0I = -1; + label pt1I = -1; + + if (ownA) + { + pt0I = fA[facePtAI]; + pt1I = fA[otherFacePtAI]; + } + else + { + pt0I = fA[otherFacePtAI]; + pt1I = fA[facePtAI]; + } + + const tetPoints tetA + ( + ccA, + tetBasePtA, + meshA.points()[pt0I], + meshA.points()[pt1I] + ); + const treeBoundBox tetABb(tetA.bounds()); + + + // Loop over tets of cellB + forAll(cFacesB, cFB) + { + label faceBI = cFacesB[cFB]; + + const face& fB = meshB.faces()[faceBI]; + const treeBoundBox pyrB = pyrBb(meshB.points(), fB, ccB); + if (!pyrB.overlaps(pyrA)) + { + continue; + } + + bool ownB = (meshB.faceOwner()[faceBI] == cellBI); + + label tetBasePtBI = 0; + + const point& tetBasePtB = meshB.points()[fB[tetBasePtBI]]; + + for (label tetPtI = 1; tetPtI < fB.size() - 1; tetPtI++) + { + label facePtBI = (tetPtI + tetBasePtBI) % fB.size(); + label otherFacePtBI = fB.fcIndex(facePtBI); + + label pt0I = -1; + label pt1I = -1; + + if (ownB) + { + pt0I = fB[facePtBI]; + pt1I = fB[otherFacePtBI]; + } + else + { + pt0I = fB[otherFacePtBI]; + pt1I = fB[facePtBI]; + } + + const tetPoints tetB + ( + ccB, + tetBasePtB, + meshB.points()[pt0I], + meshB.points()[pt1I] + ); + if (!tetB.bounds().overlaps(tetABb)) + { + continue; + } + + vol += tetTetOverlapVol(tetA, tetB); + } + } + } + } + + return vol; +} + + +Foam::labelList Foam::tetOverlapVolume::overlappingCells +( + const fvMesh& fromMesh, + const fvMesh& toMesh, + const label iTo +) const +{ + const indexedOctree<treeDataCell>& treeA = fromMesh.cellTree(); + + treeBoundBox bbB + ( + pointField(toMesh.points(), toMesh.cellPoints()[iTo]) + ); + + return treeA.findBox(bbB); +} + + +/* + + forAll(cellsA, i) + { + label cellAI = cellsA[i]; + treeBoundBox bbA + ( + pointField(meshA.points(), meshA.cellPoints()[cellAI]) + ); + + scalar v = cellCellOverlapVolumeMinDecomp + ( + meshA, + cellAI, + bbA, + meshB, + cellBI, + bbB + ); + + overlapVol += v; + nOverlapTests++; + } + +*/ + +// ************************************************************************* // diff --git a/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.H b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.H new file mode 100644 index 00000000000..d0891c14d14 --- /dev/null +++ b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetOverlapVolume.H @@ -0,0 +1,218 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2011 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/>. + + +Class + Foam::tetOverlapVolume + +Description + Calculates overlap volume of two tets. + +SourceFiles + tetOverlapVolume.C + +\*---------------------------------------------------------------------------*/ + +#ifndef tetOverlapVolume_H +#define tetOverlapVolume_H + +#include "tetrahedron.H" +#include "fvMesh.H" +#include "plane.H" +#include "tetPointRef.H" +#include "OFstream.H" +#include "meshTools.H" +#include "indexedOctree.H" +#include "treeDataCell.H" +#include "tetPoints.H" +#include "tetCell.H" +#include "EdgeMap.H" + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class tetOverlapVolume Declaration +\*---------------------------------------------------------------------------*/ + +class tetOverlapVolume +{ + // Private member functions + + //- Plane intersection + inline point planeIntersection + ( + const FixedList<scalar, 4>& d, + const tetPoints& t, + const label negI, + const label posI + ); + + + //- Decompose prism + template <class TetOp> inline void decomposePrism + ( + const FixedList<point, 6>& points, + TetOp& op + ); + + + //- Helping cľasses + class dummyTetOp + { + public: + + inline void operator()(const tetPoints&){} + }; + + + class sumTetVolOp + { + public: + scalar vol_; + + inline sumTetVolOp() + : + vol_(0.0) + {} + + inline void operator()(const tetPoints& tet) + { + vol_ += tet.tet().mag(); + } + }; + + + class storeTetOp + { + FixedList<tetPoints, 200>& tets_; + label& nTets_; + + public: + + inline storeTetOp(FixedList<tetPoints, 200>& tets, label& nTets) + : + tets_(tets), + nTets_(nTets) + {} + + inline void operator()(const tetPoints& tet) + { + tets_[nTets_++] = tet; + } + }; + + + //- Slice. Split tet into subtets above and below plane + template <class AboveTetOp, class BelowTetOp> + inline void tetSliceWithPlane + ( + const tetPoints& tet, + const plane& pl, + + AboveTetOp& aboveOp, + BelowTetOp& belowOp + ); + + + //- Tet overlap + void tetTetOverlap + ( + const tetPoints& tetA, + const tetPoints& tetB, + FixedList<tetPoints, 200>& insideTets, + label& nInside, + FixedList<tetPoints, 200>& outsideTets, + label& nOutside + ); + + + //- Tet Overlap Vol + inline scalar tetTetOverlapVol + ( + const tetPoints& tetA, + const tetPoints& tetB + ); + + + //- Return a const treeBoundBox + inline const treeBoundBox pyrBb + ( + const pointField& points, + const face& f, + const point& fc + ); + + +public: + + + //- Runtime type information + TypeName("tetOverlapVolume"); + + + // Constructors + + //- Null constructor + tetOverlapVolume(); + + + //- Destructor + virtual ~tetOverlapVolume(); + + + // Public members + + //- Return a list of cells in meshA which overlaps with cellBI in + // meshB + labelList overlappingCells + ( + const fvMesh& meshA, + const fvMesh& meshB, + const label cellBI + ) const; + + + //- Calculates the overlap volume + scalar cellCellOverlapVolumeMinDecomp + ( + const primitiveMesh& meshA, + const label cellAI, + + const primitiveMesh& meshB, + const label cellBI, + const treeBoundBox& cellBbB + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetPoints.H b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetPoints.H new file mode 100644 index 00000000000..81499832688 --- /dev/null +++ b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetPoints.H @@ -0,0 +1,114 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2011-2011 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 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/>. + +Class + Foam::tetPoints + +Description + Tet storage. Null constructable (unfortunately tetrahedron<point, point> + is not) + +SourceFiles + +\*---------------------------------------------------------------------------*/ + +#ifndef tetPoints_H +#define tetPoints_H + +#include "FixedList.H" +#include "treeBoundBox.H" +#include "tetPointRef.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class tetPoints Declaration +\*---------------------------------------------------------------------------*/ + +class tetPoints +: + public FixedList<point, 4> +{ +public: + + // Constructors + + //- Construct null + inline tetPoints() + {} + + //- Construct from four points + inline tetPoints + ( + const point& a, + const point& b, + const point& c, + const point& d + ) + { + operator[](0) = a; + operator[](1) = b; + operator[](2) = c; + operator[](3) = d; + } + + // Member Functions + + //- Return the tetrahedron + inline tetPointRef tet() const + { + return tetPointRef + ( + operator[](0), + operator[](1), + operator[](2), + operator[](3) + ); + } + + //- Calculate the bounding box + inline treeBoundBox bounds() const + { + treeBoundBox bb(operator[](0), operator[](0)); + for (label i = 1; i < size(); i++) + { + bb.min() = min(bb.min(), operator[](i)); + bb.max() = max(bb.max(), operator[](i)); + } + return bb; + } +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.C b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.C new file mode 100644 index 00000000000..14c59d5eca8 --- /dev/null +++ b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.C @@ -0,0 +1,341 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2004-2010 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 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/>. + +Description + Calculation of shape function product for a tetrahedron + +\*---------------------------------------------------------------------------*/ + +#include "tetrahedron.H" +#include "triPointRef.H" +#include "scalarField.H" + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +// (Probably very inefficient) minimum containment sphere calculation. +// From http://www.imr.sandia.gov/papers/imr11/shewchuk2.pdf: +// Sphere ctr is smallest one of +// - tet circumcentre +// - triangle circumcentre +// - edge mids +template<class Point, class PointRef> +Foam::pointHit Foam::tetrahedron<Point, PointRef>::containmentSphere +( + const scalar tol +) const +{ + const scalar fac = 1 + tol; + + // Halve order of tolerance for comparisons of sqr. + const scalar facSqr = Foam::sqrt(fac); + + + // 1. Circumcentre itself. + + pointHit pHit(circumCentre()); + pHit.setHit(); + scalar minRadiusSqr = magSqr(pHit.rawPoint() - a_); + + + // 2. Try circumcentre of tet triangles. Create circumcircle for triFace and + // check if 4th point is inside. + + { + point ctr = triPointRef(a_, b_, c_).circumCentre(); + scalar radiusSqr = magSqr(ctr - a_); + + if + ( + radiusSqr < minRadiusSqr + && Foam::magSqr(d_-ctr) <= facSqr*radiusSqr + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + { + point ctr = triPointRef(a_, b_, d_).circumCentre(); + scalar radiusSqr = magSqr(ctr - a_); + + if + ( + radiusSqr < minRadiusSqr + && Foam::magSqr(c_-ctr) <= facSqr*radiusSqr + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + { + point ctr = triPointRef(a_, c_, d_).circumCentre(); + scalar radiusSqr = magSqr(ctr - a_); + + if + ( + radiusSqr < minRadiusSqr + && Foam::magSqr(b_-ctr) <= facSqr*radiusSqr + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + { + point ctr = triPointRef(b_, c_, d_).circumCentre(); + scalar radiusSqr = magSqr(ctr - b_); + + if + ( + radiusSqr < minRadiusSqr + && Foam::magSqr(a_-ctr) <= facSqr*radiusSqr + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + + + // 3. Try midpoints of edges + + // mid of edge A-B + { + point ctr = 0.5*(a_ + b_); + scalar radiusSqr = magSqr(a_ - ctr); + scalar testRadSrq = facSqr*radiusSqr; + + if + ( + radiusSqr < minRadiusSqr + && magSqr(c_-ctr) <= testRadSrq + && magSqr(d_-ctr) <= testRadSrq) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + + // mid of edge A-C + { + point ctr = 0.5*(a_ + c_); + scalar radiusSqr = magSqr(a_ - ctr); + scalar testRadSrq = facSqr*radiusSqr; + + if + ( + radiusSqr < minRadiusSqr + && magSqr(b_-ctr) <= testRadSrq + && magSqr(d_-ctr) <= testRadSrq + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + + // mid of edge A-D + { + point ctr = 0.5*(a_ + d_); + scalar radiusSqr = magSqr(a_ - ctr); + scalar testRadSrq = facSqr*radiusSqr; + + if + ( + radiusSqr < minRadiusSqr + && magSqr(b_-ctr) <= testRadSrq + && magSqr(c_-ctr) <= testRadSrq + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + + // mid of edge B-C + { + point ctr = 0.5*(b_ + c_); + scalar radiusSqr = magSqr(b_ - ctr); + scalar testRadSrq = facSqr*radiusSqr; + + if + ( + radiusSqr < minRadiusSqr + && magSqr(a_-ctr) <= testRadSrq + && magSqr(d_-ctr) <= testRadSrq + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + + // mid of edge B-D + { + point ctr = 0.5*(b_ + d_); + scalar radiusSqr = magSqr(b_ - ctr); + scalar testRadSrq = facSqr*radiusSqr; + + if + ( + radiusSqr < minRadiusSqr + && magSqr(a_-ctr) <= testRadSrq + && magSqr(c_-ctr) <= testRadSrq) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + + // mid of edge C-D + { + point ctr = 0.5*(c_ + d_); + scalar radiusSqr = magSqr(c_ - ctr); + scalar testRadSrq = facSqr*radiusSqr; + + if + ( + radiusSqr < minRadiusSqr + && magSqr(a_-ctr) <= testRadSrq + && magSqr(b_-ctr) <= testRadSrq + ) + { + pHit.setMiss(false); + pHit.setPoint(ctr); + minRadiusSqr = radiusSqr; + } + } + + + pHit.setDistance(sqrt(minRadiusSqr)); + + return pHit; +} + + +template<class Point, class PointRef> +void Foam::tetrahedron<Point, PointRef>::gradNiSquared +( + scalarField& buffer +) const +{ + // Change of sign between face area vector and gradient + // does not matter because of square + + // Warning: Added a mag to produce positive coefficients even if + // the tetrahedron is twisted inside out. This is pretty + // dangerous, but essential for mesh motion. + scalar magVol = Foam::mag(mag()); + + buffer[0] = (1.0/9.0)*magSqr(Sa())/magVol; + buffer[1] = (1.0/9.0)*magSqr(Sb())/magVol; + buffer[2] = (1.0/9.0)*magSqr(Sc())/magVol; + buffer[3] = (1.0/9.0)*magSqr(Sd())/magVol; +} + + +template<class Point, class PointRef> +void Foam::tetrahedron<Point, PointRef>::gradNiDotGradNj +( + scalarField& buffer +) const +{ + // Warning. Ordering of edges needs to be the same for a tetrahedron + // class, a tetrahedron cell shape model and a tetCell + + // Warning: Added a mag to produce positive coefficients even if + // the tetrahedron is twisted inside out. This is pretty + // dangerous, but essential for mesh motion. + + // Double change of sign between face area vector and gradient + + scalar magVol = Foam::mag(mag()); + vector sa = Sa(); + vector sb = Sb(); + vector sc = Sc(); + vector sd = Sd(); + + buffer[0] = (1.0/9.0)*(sa & sb)/magVol; + buffer[1] = (1.0/9.0)*(sa & sc)/magVol; + buffer[2] = (1.0/9.0)*(sa & sd)/magVol; + buffer[3] = (1.0/9.0)*(sd & sb)/magVol; + buffer[4] = (1.0/9.0)*(sb & sc)/magVol; + buffer[5] = (1.0/9.0)*(sd & sc)/magVol; +} + + +template<class Point, class PointRef> +void Foam::tetrahedron<Point, PointRef>::gradNiGradNi +( + tensorField& buffer +) const +{ + // Change of sign between face area vector and gradient + // does not matter because of square + + scalar magVol = Foam::mag(mag()); + + buffer[0] = (1.0/9.0)*sqr(Sa())/magVol; + buffer[1] = (1.0/9.0)*sqr(Sb())/magVol; + buffer[2] = (1.0/9.0)*sqr(Sc())/magVol; + buffer[3] = (1.0/9.0)*sqr(Sd())/magVol; +} + + +template<class Point, class PointRef> +void Foam::tetrahedron<Point, PointRef>::gradNiGradNj +( + tensorField& buffer +) const +{ + // Warning. Ordering of edges needs to be the same for a tetrahedron + // class, a tetrahedron cell shape model and a tetCell + + // Double change of sign between face area vector and gradient + + scalar magVol = Foam::mag(mag()); + vector sa = Sa(); + vector sb = Sb(); + vector sc = Sc(); + vector sd = Sd(); + + buffer[0] = (1.0/9.0)*(sa * sb)/magVol; + buffer[1] = (1.0/9.0)*(sa * sc)/magVol; + buffer[2] = (1.0/9.0)*(sa * sd)/magVol; + buffer[3] = (1.0/9.0)*(sd * sb)/magVol; + buffer[4] = (1.0/9.0)*(sb * sc)/magVol; + buffer[5] = (1.0/9.0)*(sd * sc)/magVol; +} + + +// ************************************************************************* // diff --git a/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.H b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.H new file mode 100644 index 00000000000..0424f91b118 --- /dev/null +++ b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedron.H @@ -0,0 +1,315 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2004-2011 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 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/>. + +Class + Foam::tetrahedron + +Description + A tetrahedron primitive. + + Ordering of edges needs to be the same for a tetrahedron + class, a tetrahedron cell shape model and a tetCell. + +SourceFiles + tetrahedronI.H + tetrahedron.C + +\*---------------------------------------------------------------------------*/ + +#ifndef tetrahedron_H +#define tetrahedron_H + +#include "point.H" +#include "primitiveFieldsFwd.H" +#include "pointHit.H" +#include "cachedRandom.H" +#include "Random.H" +#include "FixedList.H" +#include "UList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class Istream; +class Ostream; +class tetPoints; +class plane; + +// Forward declaration of friend functions and operators + +template<class Point, class PointRef> class tetrahedron; + +template<class Point, class PointRef> +inline Istream& operator>> +( + Istream&, + tetrahedron<Point, PointRef>& +); + +template<class Point, class PointRef> +inline Ostream& operator<< +( + Ostream&, + const tetrahedron<Point, PointRef>& +); + + +/*---------------------------------------------------------------------------*\ + class tetrahedron Declaration +\*---------------------------------------------------------------------------*/ + +template<class Point, class PointRef> +class tetrahedron +{ +public: + + // Classes for use in sliceWithPlane. What to do with decomposition + // of tet. + + //- Dummy + class dummyOp + { + public: + inline void operator()(const tetPoints&); + }; + + //- Sum resulting volumes + class sumVolOp + { + public: + scalar vol_; + + inline sumVolOp(); + + inline void operator()(const tetPoints&); + }; + + //- Store resulting tets + class storeOp + { + FixedList<tetPoints, 200>& tets_; + label& nTets_; + + public: + inline storeOp(FixedList<tetPoints, 200>&, label&); + + inline void operator()(const tetPoints&); + }; + +private: + + // Private data + + PointRef a_, b_, c_, d_; + + inline static point planeIntersection + ( + const FixedList<scalar, 4>&, + const tetPoints&, + const label, + const label + ); + + template<class TetOp> + inline static void decomposePrism + ( + const FixedList<point, 6>& points, + TetOp& op + ); + + template<class AboveTetOp, class BelowTetOp> + inline static void tetSliceWithPlane + ( + const plane& pl, + const tetPoints& tet, + AboveTetOp& aboveOp, + BelowTetOp& belowOp + ); + + +public: + + // Member constants + + enum + { + nVertices = 4, // Number of vertices in tetrahedron + nEdges = 6 // Number of edges in tetrahedron + }; + + + // Constructors + + //- Construct from points + inline tetrahedron + ( + const Point& a, + const Point& b, + const Point& c, + const Point& d + ); + + //- Construct from four points in the list of points + inline tetrahedron + ( + const UList<Point>&, + const FixedList<label, 4>& indices + ); + + //- Construct from Istream + inline tetrahedron(Istream&); + + + // Member Functions + + // Access + + //- Return vertices + inline const Point& a() const; + + inline const Point& b() const; + + inline const Point& c() const; + + inline const Point& d() const; + + + // Properties + + //- Return face normal + inline vector Sa() const; + + inline vector Sb() const; + + inline vector Sc() const; + + inline vector Sd() const; + + //- Return centre (centroid) + inline Point centre() const; + + //- Return volume + inline scalar mag() const; + + //- Return circum-centre + inline Point circumCentre() const; + + //- Return circum-radius + inline scalar circumRadius() const; + + //- Return quality: Ratio of tetrahedron and circum-sphere + // volume, scaled so that a regular tetrahedron has a + // quality of 1 + inline scalar quality() const; + + //- Return a random point in the tetrahedron from a + // uniform distribution + inline Point randomPoint(Random& rndGen) const; + + //- Return a random point in the tetrahedron from a + // uniform distribution + inline Point randomPoint(cachedRandom& rndGen) const; + + //- Calculate the barycentric coordinates of the given + // point, in the same order as a, b, c, d. Returns the + // determinant of the solution. + inline scalar barycentric + ( + const point& pt, + List<scalar>& bary + ) const; + + //- Return nearest point to p on tetrahedron + inline pointHit nearestPoint(const point& p) const; + + //- Return true if point is inside tetrahedron + inline bool inside(const point& pt) const; + + //- Decompose tet into tets above and below plane + template<class AboveTetOp, class BelowTetOp> + inline void sliceWithPlane + ( + const plane& pl, + AboveTetOp& aboveOp, + BelowTetOp& belowOp + ) const; + + + //- Return (min)containment sphere, i.e. the smallest sphere with + // all points inside. Returns pointHit with: + // - hit : if sphere is equal to circumsphere + // (biggest sphere) + // - point : centre of sphere + // - distance : radius of sphere + // - eligiblemiss: false + // Tol (small compared to 1, e.g. 1E-9) is used to determine + // whether point is inside: mag(pt - ctr) < (1+tol)*radius. + pointHit containmentSphere(const scalar tol) const; + + //- Fill buffer with shape function products + void gradNiSquared(scalarField& buffer) const; + + void gradNiDotGradNj(scalarField& buffer) const; + + void gradNiGradNi(tensorField& buffer) const; + + void gradNiGradNj(tensorField& buffer) const; + + + // IOstream operators + + friend Istream& operator>> <Point, PointRef> + ( + Istream&, + tetrahedron& + ); + + friend Ostream& operator<< <Point, PointRef> + ( + Ostream&, + const tetrahedron& + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "tetrahedronI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository +# include "tetrahedron.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedronI.H b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedronI.H new file mode 100644 index 00000000000..6bd780aa550 --- /dev/null +++ b/src/sampling/meshToMeshInterpolation/tetOverlapVolume/tetrahedronI.H @@ -0,0 +1,1012 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2004-2011 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 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 "triangle.H" +#include "IOstreams.H" +#include "triPointRef.H" +#include "tetPoints.H" +#include "plane.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +template<class Point, class PointRef> +inline Foam::tetrahedron<Point, PointRef>::tetrahedron +( + const Point& a, + const Point& b, + const Point& c, + const Point& d +) +: + a_(a), + b_(b), + c_(c), + d_(d) +{} + + +template<class Point, class PointRef> +inline Foam::tetrahedron<Point, PointRef>::tetrahedron +( + const UList<Point>& points, + const FixedList<label, 4>& indices +) +: + a_(points[indices[0]]), + b_(points[indices[1]]), + c_(points[indices[2]]), + d_(points[indices[3]]) +{} + + +template<class Point, class PointRef> +inline Foam::tetrahedron<Point, PointRef>::tetrahedron(Istream& is) +{ + is >> *this; +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +template<class Point, class PointRef> +inline const Point& Foam::tetrahedron<Point, PointRef>::a() const +{ + return a_; +} + + +template<class Point, class PointRef> +inline const Point& Foam::tetrahedron<Point, PointRef>::b() const +{ + return b_; +} + + +template<class Point, class PointRef> +inline const Point& Foam::tetrahedron<Point, PointRef>::c() const +{ + return c_; +} + + +template<class Point, class PointRef> +inline const Point& Foam::tetrahedron<Point, PointRef>::d() const +{ + return d_; +} + + +template<class Point, class PointRef> +inline Foam::vector Foam::tetrahedron<Point, PointRef>::Sa() const +{ + return triangle<Point, PointRef>(b_, c_, d_).normal(); +} + + +template<class Point, class PointRef> +inline Foam::vector Foam::tetrahedron<Point, PointRef>::Sb() const +{ + return triangle<Point, PointRef>(a_, d_, c_).normal(); +} + + +template<class Point, class PointRef> +inline Foam::vector Foam::tetrahedron<Point, PointRef>::Sc() const +{ + return triangle<Point, PointRef>(a_, b_, d_).normal(); +} + + +template<class Point, class PointRef> +inline Foam::vector Foam::tetrahedron<Point, PointRef>::Sd() const +{ + return triangle<Point, PointRef>(a_, c_, b_).normal(); +} + + +template<class Point, class PointRef> +inline Point Foam::tetrahedron<Point, PointRef>::centre() const +{ + return 0.25*(a_ + b_ + c_ + d_); +} + + +template<class Point, class PointRef> +inline Foam::scalar Foam::tetrahedron<Point, PointRef>::mag() const +{ + return (1.0/6.0)*(((b_ - a_) ^ (c_ - a_)) & (d_ - a_)); +} + + +template<class Point, class PointRef> +inline Point Foam::tetrahedron<Point, PointRef>::circumCentre() const +{ + vector a = b_ - a_; + vector b = c_ - a_; + vector c = d_ - a_; + + scalar lambda = magSqr(c) - (a & c); + scalar mu = magSqr(b) - (a & b); + + vector ba = b ^ a; + vector ca = c ^ a; + + vector num = lambda*ba - mu*ca; + scalar denom = (c & ba); + + if (Foam::mag(denom) < ROOTVSMALL) + { + // Degenerate tetrahedron, returning centre instead of circumCentre. + + return centre(); + } + + return a_ + 0.5*(a + num/denom); +} + + +template<class Point, class PointRef> +inline Foam::scalar Foam::tetrahedron<Point, PointRef>::circumRadius() const +{ + vector a = b_ - a_; + vector b = c_ - a_; + vector c = d_ - a_; + + scalar lambda = magSqr(c) - (a & c); + scalar mu = magSqr(b) - (a & b); + + vector ba = b ^ a; + vector ca = c ^ a; + + vector num = lambda*ba - mu*ca; + scalar denom = (c & ba); + + if (Foam::mag(denom) < ROOTVSMALL) + { + // Degenerate tetrahedron, returning GREAT for circumRadius. + return GREAT; + } + + return Foam::mag(0.5*(a + num/denom)); +} + + +template<class Point, class PointRef> +inline Foam::scalar Foam::tetrahedron<Point, PointRef>::quality() const +{ + return + mag() + /( + 8.0/(9.0*sqrt(3.0)) + *pow3(min(circumRadius(), GREAT)) + + ROOTVSMALL + ); +} + + +template<class Point, class PointRef> +inline Point Foam::tetrahedron<Point, PointRef>::randomPoint +( + Random& rndGen +) const +{ + // Adapted from + // http://vcg.isti.cnr.it/activities/geometryegraphics/pointintetraedro.html + + scalar s = rndGen.scalar01(); + scalar t = rndGen.scalar01(); + scalar u = rndGen.scalar01(); + + if (s + t > 1.0) + { + s = 1.0 - s; + t = 1.0 - t; + } + + if (t + u > 1.0) + { + scalar tmp = u; + u = 1.0 - s - t; + t = 1.0 - tmp; + } + else if (s + t + u > 1.0) + { + scalar tmp = u; + u = s + t + u - 1.0; + s = 1.0 - t - tmp; + } + + return (1 - s - t - u)*a_ + s*b_ + t*c_ + u*d_; +} + + +template<class Point, class PointRef> +inline Point Foam::tetrahedron<Point, PointRef>::randomPoint +( + cachedRandom& rndGen +) const +{ + // Adapted from + // http://vcg.isti.cnr.it/activities/geometryegraphics/pointintetraedro.html + + scalar s = rndGen.sample01<scalar>(); + scalar t = rndGen.sample01<scalar>(); + scalar u = rndGen.sample01<scalar>(); + + if (s + t > 1.0) + { + s = 1.0 - s; + t = 1.0 - t; + } + + if (t + u > 1.0) + { + scalar tmp = u; + u = 1.0 - s - t; + t = 1.0 - tmp; + } + else if (s + t + u > 1.0) + { + scalar tmp = u; + u = s + t + u - 1.0; + s = 1.0 - t - tmp; + } + + return (1 - s - t - u)*a_ + s*b_ + t*c_ + u*d_; +} + + +template<class Point, class PointRef> +Foam::scalar Foam::tetrahedron<Point, PointRef>::barycentric +( + const point& pt, + List<scalar>& bary +) const +{ + // From: + // http://en.wikipedia.org/wiki/Barycentric_coordinate_system_(mathematics) + + vector e0(a_ - d_); + vector e1(b_ - d_); + vector e2(c_ - d_); + + tensor t + ( + e0.x(), e1.x(), e2.x(), + e0.y(), e1.y(), e2.y(), + e0.z(), e1.z(), e2.z() + ); + + scalar detT = det(t); + + if (Foam::mag(detT) < SMALL) + { + // Degenerate tetrahedron, returning 1/4 barycentric coordinates. + + bary = List<scalar>(4, 0.25); + + return detT; + } + + vector res = inv(t, detT) & (pt - d_); + + bary.setSize(4); + + bary[0] = res.x(); + bary[1] = res.y(); + bary[2] = res.z(); + bary[3] = (1.0 - res.x() - res.y() - res.z()); + + return detT; +} + + +template<class Point, class PointRef> +inline Foam::pointHit Foam::tetrahedron<Point, PointRef>::nearestPoint +( + const point& p +) const +{ + // Adapted from: + // Real-time collision detection, Christer Ericson, 2005, p142-144 + + // Assuming initially that the point is inside all of the + // halfspaces, so closest to itself. + + point closestPt = p; + + scalar minOutsideDistance = VGREAT; + + bool inside = true; + + if (((p - b_) & Sa()) >= 0) + { + // p is outside halfspace plane of tri + pointHit info = triangle<Point, PointRef>(b_, c_, d_).nearestPoint(p); + + inside = false; + + if (info.distance() < minOutsideDistance) + { + closestPt = info.rawPoint(); + + minOutsideDistance = info.distance(); + } + } + + if (((p - a_) & Sb()) >= 0) + { + // p is outside halfspace plane of tri + pointHit info = triangle<Point, PointRef>(a_, d_, c_).nearestPoint(p); + + inside = false; + + if (info.distance() < minOutsideDistance) + { + closestPt = info.rawPoint(); + + minOutsideDistance = info.distance(); + } + } + + if (((p - a_) & Sc()) >= 0) + { + // p is outside halfspace plane of tri + pointHit info = triangle<Point, PointRef>(a_, b_, d_).nearestPoint(p); + + inside = false; + + if (info.distance() < minOutsideDistance) + { + closestPt = info.rawPoint(); + + minOutsideDistance = info.distance(); + } + } + + if (((p - a_) & Sd()) >= 0) + { + // p is outside halfspace plane of tri + pointHit info = triangle<Point, PointRef>(a_, c_, b_).nearestPoint(p); + + inside = false; + + if (info.distance() < minOutsideDistance) + { + closestPt = info.rawPoint(); + + minOutsideDistance = info.distance(); + } + } + + // If the point is inside, then the distance to the closest point + // is zero + if (inside) + { + minOutsideDistance = 0; + } + + return pointHit + ( + inside, + closestPt, + minOutsideDistance, + !inside + ); +} + + +template<class Point, class PointRef> +bool Foam::tetrahedron<Point, PointRef>::inside(const point& pt) const +{ + // For robustness, assuming that the point is in the tet unless + // "definitively" shown otherwise by obtaining a positive dot + // product greater than a tolerance of SMALL. + + // The tet is defined: tet(Cc, tetBasePt, pA, pB) where the normal + // vectors and base points for the half-space planes are: + // area[0] = Sa(); + // area[1] = Sb(); + // area[2] = Sc(); + // area[3] = Sd(); + // planeBase[0] = tetBasePt = b_ + // planeBase[1] = ptA = c_ + // planeBase[2] = tetBasePt = b_ + // planeBase[3] = tetBasePt = b_ + + vector n = vector::zero; + + { + // 0, a + const point& basePt = b_; + + n = Sa(); + n /= (Foam::mag(n) + VSMALL); + + if (((pt - basePt) & n) > SMALL) + { + return false; + } + } + + { + // 1, b + const point& basePt = c_; + + n = Sb(); + n /= (Foam::mag(n) + VSMALL); + + if (((pt - basePt) & n) > SMALL) + { + return false; + } + } + + { + // 2, c + const point& basePt = b_; + + n = Sc(); + n /= (Foam::mag(n) + VSMALL); + + if (((pt - basePt) & n) > SMALL) + { + return false; + } + } + + { + // 3, d + const point& basePt = b_; + + n = Sd(); + n /= (Foam::mag(n) + VSMALL); + + if (((pt - basePt) & n) > SMALL) + { + return false; + } + } + + return true; +} + + +template<class Point, class PointRef> +inline void Foam::tetrahedron<Point, PointRef>::dummyOp::operator() +( + const tetPoints& +) +{} + + +template<class Point, class PointRef> +inline Foam::tetrahedron<Point, PointRef>::sumVolOp::sumVolOp() +: + vol_(0.0) +{} + + +template<class Point, class PointRef> +inline void Foam::tetrahedron<Point, PointRef>::sumVolOp::operator() +( + const tetPoints& tet +) +{ + vol_ += tet.tet().mag(); +} + + +template<class Point, class PointRef> +inline Foam::tetrahedron<Point, PointRef>::storeOp::storeOp +( + FixedList<tetPoints, 200>& tets, + label& nTets +) +: + tets_(tets), + nTets_(nTets) +{} + + +template<class Point, class PointRef> +inline void Foam::tetrahedron<Point, PointRef>::storeOp::operator() +( + const tetPoints& tet +) +{ + tets_[nTets_++] = tet; +} + + +template<class Point, class PointRef> +inline Foam::point Foam::tetrahedron<Point, PointRef>::planeIntersection +( + const FixedList<scalar, 4>& d, + const tetPoints& t, + const label negI, + const label posI +) +{ + return + (d[posI]*t[negI] - d[negI]*t[posI]) + / (-d[negI]+d[posI]); +} + + +template<class Point, class PointRef> +template<class TetOp> +inline void Foam::tetrahedron<Point, PointRef>::decomposePrism +( + const FixedList<point, 6>& points, + TetOp& op +) +{ + op(tetPoints(points[1], points[3], points[2], points[0])); + op(tetPoints(points[1], points[2], points[3], points[4])); + op(tetPoints(points[4], points[2], points[3], points[5])); +} + + +template<class Point, class PointRef> +template<class AboveTetOp, class BelowTetOp> +inline void Foam::tetrahedron<Point, PointRef>:: +tetSliceWithPlane +( + const plane& pl, + const tetPoints& tet, + AboveTetOp& aboveOp, + BelowTetOp& belowOp +) +{ + // Distance to plane + FixedList<scalar, 4> d; + label nPos = 0; + forAll(tet, i) + { + d[i] = ((tet[i]-pl.refPoint()) & pl.normal()); + if (d[i] > 0) + { + nPos++; + } + } + + if (nPos == 4) + { + aboveOp(tet); + } + else if (nPos == 3) + { + // Sliced into below tet and above prism. Prism gets split into + // two tets. + + // Find the below tet + label i0 = -1; + forAll(d, i) + { + if (d[i] <= 0) + { + i0 = i; + break; + } + } + + label i1 = d.fcIndex(i0); + label i2 = d.fcIndex(i1); + label i3 = d.fcIndex(i2); + + point p01 = planeIntersection(d, tet, i0, i1); + point p02 = planeIntersection(d, tet, i0, i2); + point p03 = planeIntersection(d, tet, i0, i3); + + // i0 = tetCell vertex 0: p01,p02,p03 outwards pointing triad + // ,, 1 : ,, inwards pointing triad + // ,, 2 : ,, outwards pointing triad + // ,, 3 : ,, inwards pointing triad + + //Pout<< "Split 3pos tet " << tet << " d:" << d << " into" << nl; + + if (i0 == 0 || i0 == 2) + { + tetPoints t(tet[i0], p01, p02, p03); + //Pout<< " belowtet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 3, belowTet i0==0 or 2"); + belowOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i1]; + p[1] = tet[i3]; + p[2] = tet[i2]; + p[3] = p01; + p[4] = p03; + p[5] = p02; + //Pout<< " aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + else + { + tetPoints t(p01, p02, p03, tet[i0]); + //Pout<< " belowtet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 3, belowTet i0==1 or 3"); + belowOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i3]; + p[1] = tet[i1]; + p[2] = tet[i2]; + p[3] = p03; + p[4] = p01; + p[5] = p02; + //Pout<< " aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + } + else if (nPos == 2) + { + // Tet cut into two prisms. Determine the positive one. + label pos0 = -1; + label pos1 = -1; + label neg0 = -1; + label neg1 = -1; + forAll(d, i) + { + if (d[i] > 0) + { + if (pos0 == -1) + { + pos0 = i; + } + else + { + pos1 = i; + } + } + else + { + if (neg0 == -1) + { + neg0 = i; + } + else + { + neg1 = i; + } + } + } + + //Pout<< "Split 2pos tet " << tet << " d:" << d + // << " around pos0:" << pos0 << " pos1:" << pos1 + // << " neg0:" << neg0 << " neg1:" << neg1 << " into" << nl; + + const edge posEdge(pos0, pos1); + + if (posEdge == edge(0, 1)) + { + point p02 = planeIntersection(d, tet, 0, 2); + point p03 = planeIntersection(d, tet, 0, 3); + point p12 = planeIntersection(d, tet, 1, 2); + point p13 = planeIntersection(d, tet, 1, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[0]; + p[1] = p02; + p[2] = p03; + p[3] = tet[1]; + p[4] = p12; + p[5] = p13; + //Pout<< " 01 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p02; + p[2] = p12; + p[3] = tet[3]; + p[4] = p03; + p[5] = p13; + //Pout<< " 01 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(1, 2)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p13 = planeIntersection(d, tet, 1, 3); + point p02 = planeIntersection(d, tet, 0, 2); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[1]; + p[1] = p01; + p[2] = p13; + p[3] = tet[2]; + p[4] = p02; + p[5] = p23; + //Pout<< " 12 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[3]; + p[1] = p23; + p[2] = p13; + p[3] = tet[0]; + p[4] = p02; + p[5] = p01; + //Pout<< " 12 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(2, 0)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p03 = planeIntersection(d, tet, 0, 3); + point p12 = planeIntersection(d, tet, 1, 2); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p12; + p[2] = p23; + p[3] = tet[0]; + p[4] = p01; + p[5] = p03; + //Pout<< " 20 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[1]; + p[1] = p12; + p[2] = p01; + p[3] = tet[3]; + p[4] = p23; + p[5] = p03; + //Pout<< " 20 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(0, 3)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p02 = planeIntersection(d, tet, 0, 2); + point p13 = planeIntersection(d, tet, 1, 3); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[3]; + p[1] = p23; + p[2] = p13; + p[3] = tet[0]; + p[4] = p02; + p[5] = p01; + //Pout<< " 03 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p23; + p[2] = p02; + p[3] = tet[1]; + p[4] = p13; + p[5] = p01; + //Pout<< " 03 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(1, 3)) + { + point p01 = planeIntersection(d, tet, 0, 1); + point p12 = planeIntersection(d, tet, 1, 2); + point p03 = planeIntersection(d, tet, 0, 3); + point p23 = planeIntersection(d, tet, 2, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[1]; + p[1] = p12; + p[2] = p01; + p[3] = tet[3]; + p[4] = p23; + p[5] = p03; + //Pout<< " 13 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p12; + p[2] = p23; + p[3] = tet[0]; + p[4] = p01; + p[5] = p03; + //Pout<< " 13 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else if (posEdge == edge(2, 3)) + { + point p02 = planeIntersection(d, tet, 0, 2); + point p12 = planeIntersection(d, tet, 1, 2); + point p03 = planeIntersection(d, tet, 0, 3); + point p13 = planeIntersection(d, tet, 1, 3); + // Split the resulting prism + { + FixedList<point, 6> p; + p[0] = tet[2]; + p[1] = p02; + p[2] = p12; + p[3] = tet[3]; + p[4] = p03; + p[5] = p13; + //Pout<< " 23 aboveprism:" << p << endl; + decomposePrism(p, aboveOp); + } + { + FixedList<point, 6> p; + p[0] = tet[0]; + p[1] = p02; + p[2] = p03; + p[3] = tet[1]; + p[4] = p12; + p[5] = p13; + //Pout<< " 23 belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else + { + FatalErrorIn("tetSliceWithPlane(..)") + << "Missed edge:" << posEdge + << abort(FatalError); + } + } + else if (nPos == 1) + { + // Find the positive tet + label i0 = -1; + forAll(d, i) + { + if (d[i] > 0) + { + i0 = i; + break; + } + } + + label i1 = d.fcIndex(i0); + label i2 = d.fcIndex(i1); + label i3 = d.fcIndex(i2); + + point p01 = planeIntersection(d, tet, i0, i1); + point p02 = planeIntersection(d, tet, i0, i2); + point p03 = planeIntersection(d, tet, i0, i3); + + //Pout<< "Split 1pos tet " << tet << " d:" << d << " into" << nl; + + if (i0 == 0 || i0 == 2) + { + tetPoints t(tet[i0], p01, p02, p03); + //Pout<< " abovetet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 1, aboveTets i0==0 or 2"); + aboveOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i1]; + p[1] = tet[i3]; + p[2] = tet[i2]; + p[3] = p01; + p[4] = p03; + p[5] = p02; + //Pout<< " belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + else + { + tetPoints t(p01, p02, p03, tet[i0]); + //Pout<< " abovetet:" << t << " around i0:" << i0 << endl; + //checkTet(t, "nPos 1, aboveTets i0==1 or 3"); + aboveOp(t); + + // Prism + FixedList<point, 6> p; + p[0] = tet[i3]; + p[1] = tet[i1]; + p[2] = tet[i2]; + p[3] = p03; + p[4] = p01; + p[5] = p02; + //Pout<< " belowprism:" << p << endl; + decomposePrism(p, belowOp); + } + } + else // nPos == 0 + { + belowOp(tet); + } +} + + +template<class Point, class PointRef> +template<class AboveTetOp, class BelowTetOp> +inline void Foam::tetrahedron<Point, PointRef>::sliceWithPlane +( + const plane& pl, + AboveTetOp& aboveOp, + BelowTetOp& belowOp +) const +{ + tetSliceWithPlane(pl, tetPoints(a_, b_, c_, d_), aboveOp, belowOp); +} + + +// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * // + +template<class Point, class PointRef> +inline Foam::Istream& Foam::operator>> +( + Istream& is, + tetrahedron<Point, PointRef>& t +) +{ + is.readBegin("tetrahedron"); + is >> t.a_ >> t.b_ >> t.c_ >> t.d_; + is.readEnd("tetrahedron"); + + is.check("Istream& operator>>(Istream&, tetrahedron&)"); + + return is; +} + + +template<class Point, class PointRef> +inline Foam::Ostream& Foam::operator<< +( + Ostream& os, + const tetrahedron<Point, PointRef>& t +) +{ + os << nl + << token::BEGIN_LIST + << t.a_ << token::SPACE + << t.b_ << token::SPACE + << t.c_ << token::SPACE + << t.d_ + << token::END_LIST; + + return os; +} + + +// ************************************************************************* // -- GitLab