mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: extrudeToRegionMesh: parallel operation
This commit is contained in:
@ -1,4 +1,3 @@
|
|||||||
patchPointEdgeCirculator.C
|
|
||||||
createShellMesh.C
|
createShellMesh.C
|
||||||
extrudeToRegionMesh.C
|
extrudeToRegionMesh.C
|
||||||
|
|
||||||
|
|||||||
@ -31,130 +31,381 @@ License
|
|||||||
#include "polyAddFace.H"
|
#include "polyAddFace.H"
|
||||||
#include "polyModifyFace.H"
|
#include "polyModifyFace.H"
|
||||||
#include "polyAddCell.H"
|
#include "polyAddCell.H"
|
||||||
#include "patchPointEdgeCirculator.H"
|
#include "labelPair.H"
|
||||||
|
#include "indirectPrimitivePatch.H"
|
||||||
|
#include "mapDistribute.H"
|
||||||
|
#include "globalMeshData.H"
|
||||||
|
#include "PatchTools.H"
|
||||||
|
#include "globalIndex.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
defineTypeNameAndDebug(Foam::createShellMesh, 0);
|
defineTypeNameAndDebug(Foam::createShellMesh, 0);
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
class minEqOp<labelPair>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator()(labelPair& x, const labelPair& y) const
|
||||||
|
{
|
||||||
|
x[0] = min(x[0], y[0]);
|
||||||
|
x[1] = min(x[1], y[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
void Foam::createShellMesh::calcPointRegions
|
// Synchronise edges
|
||||||
|
void Foam::createShellMesh::syncEdges
|
||||||
(
|
(
|
||||||
const primitiveFacePatch& patch,
|
const globalMeshData& globalData,
|
||||||
const PackedBoolList& nonManifoldEdge,
|
|
||||||
faceList& pointRegions,
|
const labelList& patchEdges,
|
||||||
labelList& regionPoints
|
const labelList& coupledEdges,
|
||||||
|
const PackedBoolList& sameEdgeOrientation,
|
||||||
|
|
||||||
|
PackedBoolList& isChangedEdge,
|
||||||
|
DynamicList<label>& changedEdges,
|
||||||
|
labelPairList& allEdgeData
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
pointRegions.setSize(patch.size());
|
const mapDistribute& map = globalData.globalEdgeSlavesMap();
|
||||||
forAll(pointRegions, faceI)
|
const PackedBoolList& cppOrientation = globalData.globalEdgeOrientation();
|
||||||
{
|
|
||||||
const face& f = patch.localFaces()[faceI];
|
|
||||||
pointRegions[faceI].setSize(f.size(), -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
label nRegions = 0;
|
// Convert patch-edge data into cpp-edge data
|
||||||
|
labelPairList cppEdgeData
|
||||||
forAll(pointRegions, faceI)
|
|
||||||
{
|
|
||||||
const face& f = patch.localFaces()[faceI];
|
|
||||||
|
|
||||||
forAll(f, fp)
|
|
||||||
{
|
|
||||||
if (pointRegions[faceI][fp] == -1)
|
|
||||||
{
|
|
||||||
// Found unassigned point. Distribute current region.
|
|
||||||
label pointI = f[fp];
|
|
||||||
label edgeI = patch.faceEdges()[faceI][fp];
|
|
||||||
|
|
||||||
patchPointEdgeCirculator circ
|
|
||||||
(
|
(
|
||||||
patch,
|
map.constructSize(),
|
||||||
nonManifoldEdge,
|
labelPair(labelMax, labelMax)
|
||||||
edgeI,
|
|
||||||
findIndex(patch.edgeFaces()[edgeI], faceI),
|
|
||||||
pointI
|
|
||||||
);
|
);
|
||||||
|
|
||||||
for
|
forAll(patchEdges, i)
|
||||||
|
{
|
||||||
|
label patchEdgeI = patchEdges[i];
|
||||||
|
label coupledEdgeI = coupledEdges[i];
|
||||||
|
|
||||||
|
if (isChangedEdge[patchEdgeI])
|
||||||
|
{
|
||||||
|
const labelPair& data = allEdgeData[patchEdgeI];
|
||||||
|
|
||||||
|
// Patch-edge data needs to be converted into coupled-edge data
|
||||||
|
// (optionally flipped) and consistent in orientation with
|
||||||
|
// other coupled edge (optionally flipped)
|
||||||
|
if (sameEdgeOrientation[i] == cppOrientation[coupledEdgeI])
|
||||||
|
{
|
||||||
|
cppEdgeData[coupledEdgeI] = data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cppEdgeData[coupledEdgeI] = labelPair(data[1], data[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronise
|
||||||
|
globalData.syncData
|
||||||
(
|
(
|
||||||
patchPointEdgeCirculator iter = circ.begin();
|
cppEdgeData,
|
||||||
iter != circ.end();
|
globalData.globalEdgeSlaves(),
|
||||||
++iter
|
globalData.globalEdgeTransformedSlaves(),
|
||||||
|
map,
|
||||||
|
minEqOp<labelPair>()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Back from cpp-edge to patch-edge data
|
||||||
|
forAll(patchEdges, i)
|
||||||
|
{
|
||||||
|
label patchEdgeI = patchEdges[i];
|
||||||
|
label coupledEdgeI = coupledEdges[i];
|
||||||
|
|
||||||
|
if (cppEdgeData[coupledEdgeI] != labelPair(labelMax, labelMax))
|
||||||
|
{
|
||||||
|
const labelPair& data = cppEdgeData[coupledEdgeI];
|
||||||
|
|
||||||
|
if (sameEdgeOrientation[i] == cppOrientation[coupledEdgeI])
|
||||||
|
{
|
||||||
|
allEdgeData[patchEdgeI] = data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allEdgeData[patchEdgeI] = labelPair(data[1], data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isChangedEdge[patchEdgeI])
|
||||||
|
{
|
||||||
|
changedEdges.append(patchEdgeI);
|
||||||
|
isChangedEdge[patchEdgeI] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::createShellMesh::calcPointRegions
|
||||||
|
(
|
||||||
|
const globalMeshData& globalData,
|
||||||
|
const primitiveFacePatch& patch,
|
||||||
|
const PackedBoolList& nonManifoldEdge,
|
||||||
|
|
||||||
|
faceList& pointGlobalRegions,
|
||||||
|
faceList& pointLocalRegions,
|
||||||
|
labelList& localToGlobalRegion
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
label face2 = iter.faceID();
|
const indirectPrimitivePatch& cpp = globalData.coupledPatch();
|
||||||
|
|
||||||
if (face2 != -1)
|
// Calculate correspondence between patch and globalData.coupledPatch.
|
||||||
{
|
labelList patchEdges;
|
||||||
const face& f2 = patch.localFaces()[face2];
|
labelList coupledEdges;
|
||||||
label fp2 = findIndex(f2, pointI);
|
PackedBoolList sameEdgeOrientation;
|
||||||
label& region = pointRegions[face2][fp2];
|
PatchTools::matchEdges
|
||||||
if (region != -1)
|
|
||||||
{
|
|
||||||
FatalErrorIn
|
|
||||||
(
|
(
|
||||||
"createShellMesh::calcPointRegions(..)"
|
cpp,
|
||||||
) << "On point " << pointI
|
patch,
|
||||||
<< " at:" << patch.localPoints()[pointI]
|
|
||||||
<< " found region:" << region
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
region = nRegions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nRegions++;
|
coupledEdges,
|
||||||
}
|
patchEdges,
|
||||||
}
|
sameEdgeOrientation
|
||||||
}
|
);
|
||||||
|
|
||||||
|
|
||||||
// From region back to originating point (many to one, a point might
|
// Initial unique regions
|
||||||
// have multiple regions though)
|
// ~~~~~~~~~~~~~~~~~~~~~~
|
||||||
regionPoints.setSize(nRegions);
|
// These get merged later on across connected edges.
|
||||||
forAll(pointRegions, faceI)
|
|
||||||
|
// 1. Count
|
||||||
|
label nMaxRegions = 0;
|
||||||
|
forAll(patch.localFaces(), faceI)
|
||||||
{
|
{
|
||||||
const face& f = patch.localFaces()[faceI];
|
const face& f = patch.localFaces()[faceI];
|
||||||
|
nMaxRegions += f.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const globalIndex globalRegions(nMaxRegions);
|
||||||
|
|
||||||
|
// 2. Assign unique regions
|
||||||
|
label nRegions = 0;
|
||||||
|
|
||||||
|
pointGlobalRegions.setSize(patch.size());
|
||||||
|
forAll(pointGlobalRegions, faceI)
|
||||||
|
{
|
||||||
|
const face& f = patch.localFaces()[faceI];
|
||||||
|
labelList& pRegions = pointGlobalRegions[faceI];
|
||||||
|
pRegions.setSize(f.size());
|
||||||
|
forAll(pRegions, fp)
|
||||||
|
{
|
||||||
|
pRegions[fp] = globalRegions.toGlobal(nRegions++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicList<label> changedEdges(patch.nEdges());
|
||||||
|
labelPairList allEdgeData(patch.nEdges(), labelPair(labelMax, labelMax));
|
||||||
|
PackedBoolList isChangedEdge(patch.nEdges());
|
||||||
|
|
||||||
|
|
||||||
|
// Fill initial seed
|
||||||
|
// ~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
forAll(patch.edgeFaces(), edgeI)
|
||||||
|
{
|
||||||
|
if (!nonManifoldEdge[edgeI])
|
||||||
|
{
|
||||||
|
// Take over value from one face only.
|
||||||
|
const edge& e = patch.edges()[edgeI];
|
||||||
|
label faceI = patch.edgeFaces()[edgeI][0];
|
||||||
|
const face& f = patch.localFaces()[faceI];
|
||||||
|
|
||||||
|
label fp0 = findIndex(f, e[0]);
|
||||||
|
label fp1 = findIndex(f, e[1]);
|
||||||
|
allEdgeData[edgeI] = labelPair
|
||||||
|
(
|
||||||
|
pointGlobalRegions[faceI][fp0],
|
||||||
|
pointGlobalRegions[faceI][fp1]
|
||||||
|
);
|
||||||
|
if (!isChangedEdge[edgeI])
|
||||||
|
{
|
||||||
|
changedEdges.append(edgeI);
|
||||||
|
isChangedEdge[edgeI] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
syncEdges
|
||||||
|
(
|
||||||
|
globalData,
|
||||||
|
|
||||||
|
patchEdges,
|
||||||
|
coupledEdges,
|
||||||
|
sameEdgeOrientation,
|
||||||
|
|
||||||
|
isChangedEdge,
|
||||||
|
changedEdges,
|
||||||
|
allEdgeData
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Edge-Face-Edge walk across patch
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Across edge minimum regions win
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// From edge to face
|
||||||
|
// ~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
DynamicList<label> changedFaces(patch.size());
|
||||||
|
PackedBoolList isChangedFace(patch.size());
|
||||||
|
|
||||||
|
forAll(changedEdges, changedI)
|
||||||
|
{
|
||||||
|
label edgeI = changedEdges[changedI];
|
||||||
|
const labelPair& edgeData = allEdgeData[edgeI];
|
||||||
|
|
||||||
|
const edge& e = patch.edges()[edgeI];
|
||||||
|
const labelList& eFaces = patch.edgeFaces()[edgeI];
|
||||||
|
|
||||||
|
forAll(eFaces, i)
|
||||||
|
{
|
||||||
|
label faceI = eFaces[i];
|
||||||
|
const face& f = patch.localFaces()[faceI];
|
||||||
|
|
||||||
|
// Combine edgeData with face data
|
||||||
|
label fp0 = findIndex(f, e[0]);
|
||||||
|
if (pointGlobalRegions[faceI][fp0] > edgeData[0])
|
||||||
|
{
|
||||||
|
pointGlobalRegions[faceI][fp0] = edgeData[0];
|
||||||
|
if (!isChangedFace[faceI])
|
||||||
|
{
|
||||||
|
isChangedFace[faceI] = true;
|
||||||
|
changedFaces.append(faceI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label fp1 = findIndex(f, e[1]);
|
||||||
|
if (pointGlobalRegions[faceI][fp1] > edgeData[1])
|
||||||
|
{
|
||||||
|
pointGlobalRegions[faceI][fp1] = edgeData[1];
|
||||||
|
if (!isChangedFace[faceI])
|
||||||
|
{
|
||||||
|
isChangedFace[faceI] = true;
|
||||||
|
changedFaces.append(faceI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
label nChangedFaces = returnReduce(changedFaces.size(), sumOp<label>());
|
||||||
|
if (nChangedFaces == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// From face to edge
|
||||||
|
// ~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
isChangedEdge = false;
|
||||||
|
changedEdges.clear();
|
||||||
|
|
||||||
|
forAll(changedFaces, i)
|
||||||
|
{
|
||||||
|
label faceI = changedFaces[i];
|
||||||
|
const face& f = patch.localFaces()[faceI];
|
||||||
|
const labelList& fEdges = patch.faceEdges()[faceI];
|
||||||
|
|
||||||
|
forAll(fEdges, fp)
|
||||||
|
{
|
||||||
|
label edgeI = fEdges[fp];
|
||||||
|
|
||||||
|
if (!nonManifoldEdge[edgeI])
|
||||||
|
{
|
||||||
|
const edge& e = patch.edges()[edgeI];
|
||||||
|
label fp0 = findIndex(f, e[0]);
|
||||||
|
label region0 = pointGlobalRegions[faceI][fp0];
|
||||||
|
label fp1 = findIndex(f, e[1]);
|
||||||
|
label region1 = pointGlobalRegions[faceI][fp1];
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
(allEdgeData[edgeI][0] > region0)
|
||||||
|
|| (allEdgeData[edgeI][1] > region1)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
allEdgeData[edgeI] = labelPair(region0, region1);
|
||||||
|
if (!isChangedEdge[edgeI])
|
||||||
|
{
|
||||||
|
changedEdges.append(edgeI);
|
||||||
|
isChangedEdge[edgeI] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syncEdges
|
||||||
|
(
|
||||||
|
globalData,
|
||||||
|
|
||||||
|
patchEdges,
|
||||||
|
coupledEdges,
|
||||||
|
sameEdgeOrientation,
|
||||||
|
|
||||||
|
isChangedEdge,
|
||||||
|
changedEdges,
|
||||||
|
allEdgeData
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
label nChangedEdges = returnReduce(changedEdges.size(), sumOp<label>());
|
||||||
|
if (nChangedEdges == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Assign local regions
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
// Calculate addressing from global region back to local region
|
||||||
|
pointLocalRegions.setSize(patch.size());
|
||||||
|
Map<label> globalToLocalRegion(globalRegions.localSize()/4);
|
||||||
|
DynamicList<label> dynLocalToGlobalRegion(globalToLocalRegion.size());
|
||||||
|
forAll(patch.localFaces(), faceI)
|
||||||
|
{
|
||||||
|
const face& f = patch.localFaces()[faceI];
|
||||||
|
face& pRegions = pointLocalRegions[faceI];
|
||||||
|
pRegions.setSize(f.size());
|
||||||
forAll(f, fp)
|
forAll(f, fp)
|
||||||
{
|
{
|
||||||
regionPoints[pointRegions[faceI][fp]] = f[fp];
|
label globalRegionI = pointGlobalRegions[faceI][fp];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Map<label>::iterator fnd = globalToLocalRegion.find(globalRegionI);
|
||||||
|
|
||||||
if (debug)
|
if (fnd != globalToLocalRegion.end())
|
||||||
{
|
{
|
||||||
const labelListList& pointFaces = patch.pointFaces();
|
// Already encountered this global region. Assign same local one
|
||||||
forAll(pointFaces, pointI)
|
pRegions[fp] = fnd();
|
||||||
{
|
|
||||||
label region = -1;
|
|
||||||
const labelList& pFaces = pointFaces[pointI];
|
|
||||||
forAll(pFaces, i)
|
|
||||||
{
|
|
||||||
label faceI = pFaces[i];
|
|
||||||
const face& f = patch.localFaces()[faceI];
|
|
||||||
label fp = findIndex(f, pointI);
|
|
||||||
|
|
||||||
if (region == -1)
|
|
||||||
{
|
|
||||||
region = pointRegions[faceI][fp];
|
|
||||||
}
|
}
|
||||||
else if (region != pointRegions[faceI][fp])
|
else
|
||||||
{
|
{
|
||||||
Pout<< "Non-manifold point:" << pointI
|
// Region not yet seen. Create new one
|
||||||
<< " at " << patch.localPoints()[pointI]
|
label localRegionI = globalToLocalRegion.size();
|
||||||
<< " region:" << region
|
pRegions[fp] = localRegionI;
|
||||||
<< " otherRegion:" << pointRegions[faceI][fp]
|
globalToLocalRegion.insert(globalRegionI, localRegionI);
|
||||||
<< endl;
|
dynLocalToGlobalRegion.append(globalRegionI);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
localToGlobalRegion.transfer(dynLocalToGlobalRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,7 @@ SourceFiles
|
|||||||
|
|
||||||
#include "primitiveFacePatch.H"
|
#include "primitiveFacePatch.H"
|
||||||
#include "PackedBoolList.H"
|
#include "PackedBoolList.H"
|
||||||
|
#include "labelPair.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ namespace Foam
|
|||||||
// Forward declaration of classes
|
// Forward declaration of classes
|
||||||
class mapPolyMesh;
|
class mapPolyMesh;
|
||||||
class polyTopoChange;
|
class polyTopoChange;
|
||||||
|
class globalMeshData;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*\
|
/*---------------------------------------------------------------------------*\
|
||||||
Class createShellMesh Declaration
|
Class createShellMesh Declaration
|
||||||
@ -80,6 +82,18 @@ class createShellMesh
|
|||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
|
static void syncEdges
|
||||||
|
(
|
||||||
|
const globalMeshData&,
|
||||||
|
const labelList&,
|
||||||
|
const labelList&,
|
||||||
|
const PackedBoolList& sameEdgeOrientation,
|
||||||
|
PackedBoolList& isChangedEdge,
|
||||||
|
DynamicList<label>& changedEdges,
|
||||||
|
labelPairList& allEdgeData
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
//- Disallow default bitwise copy construct
|
//- Disallow default bitwise copy construct
|
||||||
createShellMesh(const createShellMesh&);
|
createShellMesh(const createShellMesh&);
|
||||||
|
|
||||||
@ -142,13 +156,22 @@ public:
|
|||||||
|
|
||||||
// Other
|
// Other
|
||||||
|
|
||||||
//- Helper: calculate point regions
|
//- Helper: calculate point regions. The point region is the
|
||||||
|
// same on all faces connected to a point if they can be
|
||||||
|
// reached through a face-edge-face walk without crossing
|
||||||
|
// the nonManifoldEdge.
|
||||||
|
// pointGlobalRegions : non-compact. Guaranteed to be the same
|
||||||
|
// across processors.
|
||||||
|
// pointLocalRegions : compact.
|
||||||
|
// localToGlobalRegion : local to global region.
|
||||||
static void calcPointRegions
|
static void calcPointRegions
|
||||||
(
|
(
|
||||||
|
const globalMeshData& globalData,
|
||||||
const primitiveFacePatch& patch,
|
const primitiveFacePatch& patch,
|
||||||
const PackedBoolList& nonManifoldEdge,
|
const PackedBoolList& nonManifoldEdge,
|
||||||
faceList& pointRegions,
|
faceList& pointGlobalRegions,
|
||||||
labelList& regionPoints
|
faceList& pointLocalRegions,
|
||||||
|
labelList& localToGlobalRegion
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Play commands into polyTopoChange to create layer mesh.
|
//- Play commands into polyTopoChange to create layer mesh.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,67 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / 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 "patchPointEdgeCirculator.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
const Foam::patchPointEdgeCirculator
|
|
||||||
Foam::patchPointEdgeCirculator::endConstIter
|
|
||||||
(
|
|
||||||
*reinterpret_cast<primitiveFacePatch*>(0), // primitiveFacePatch
|
|
||||||
*reinterpret_cast<PackedBoolList*>(0), // PackedBoolList
|
|
||||||
-1, // edgeID
|
|
||||||
-1, // index
|
|
||||||
-1 // pointID
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
Foam::Ostream& Foam::operator<<
|
|
||||||
(
|
|
||||||
Ostream& os,
|
|
||||||
const InfoProxy<patchPointEdgeCirculator>& ip
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const patchPointEdgeCirculator& c = ip.t_;
|
|
||||||
|
|
||||||
const pointField& pts = c.patch_.localPoints();
|
|
||||||
const edge& e = c.patch_.edges()[c.edgeID_];
|
|
||||||
label faceI = c.faceID();
|
|
||||||
|
|
||||||
os << "around point:" << c.pointID_
|
|
||||||
<< " coord:" << pts[c.pointID_]
|
|
||||||
<< " at edge:" << c.edgeID_
|
|
||||||
<< " coord:" << pts[e.otherVertex(c.pointID_)]
|
|
||||||
<< " in direction of face:" << faceI;
|
|
||||||
|
|
||||||
if (faceI != -1)
|
|
||||||
{
|
|
||||||
os << " fc:" << c.patch_.localFaces()[faceI].centre(pts);
|
|
||||||
}
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,205 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / 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::patchPointEdgeCirculator
|
|
||||||
|
|
||||||
Description
|
|
||||||
Walks from starting edge/face around point on patch.
|
|
||||||
|
|
||||||
-# Use in-place: \n
|
|
||||||
\code
|
|
||||||
patchPointEdgeCirculator circ(..);
|
|
||||||
|
|
||||||
// Walk
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Info<< "edge:" << circ.edgeID() << endl;
|
|
||||||
++circ;
|
|
||||||
}
|
|
||||||
while (circ != circ.end());
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
-# Use like STL iterator: \n
|
|
||||||
\code
|
|
||||||
patchPointEdgeCirculator circ(..);
|
|
||||||
for
|
|
||||||
(
|
|
||||||
patchPointEdgeCirculator iter = circ.begin();
|
|
||||||
iter != circ.end();
|
|
||||||
++iter
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Info<< "edge:" << iter.edgeID() << endl;
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
|
|
||||||
SourceFiles
|
|
||||||
patchPointEdgeCirculator.C
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef patchPointEdgeCirculator_H
|
|
||||||
#define patchPointEdgeCirculator_H
|
|
||||||
|
|
||||||
#include "face.H"
|
|
||||||
#include "ListOps.H"
|
|
||||||
#include "primitiveFacePatch.H"
|
|
||||||
#include "PackedBoolList.H"
|
|
||||||
#include "InfoProxy.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
namespace Foam
|
|
||||||
{
|
|
||||||
|
|
||||||
// Forward declaration of classes
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
Class patchPointEdgeCirculator Declaration
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
class patchPointEdgeCirculator
|
|
||||||
{
|
|
||||||
// Static data members
|
|
||||||
|
|
||||||
//- end iterator
|
|
||||||
static const patchPointEdgeCirculator endConstIter;
|
|
||||||
|
|
||||||
|
|
||||||
// Private data
|
|
||||||
|
|
||||||
//- Patch
|
|
||||||
const primitiveFacePatch& patch_;
|
|
||||||
|
|
||||||
const PackedBoolList& nonManifoldEdge_;
|
|
||||||
|
|
||||||
//- Current edge
|
|
||||||
label edgeID_;
|
|
||||||
|
|
||||||
//- Current direction (face, expressed as index into edgeFaces()[edgeID]
|
|
||||||
label index_;
|
|
||||||
|
|
||||||
//- Point
|
|
||||||
label pointID_;
|
|
||||||
|
|
||||||
//- Starting edge so we know when to stop.
|
|
||||||
label startEdgeID_;
|
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
|
||||||
|
|
||||||
//- Set to end() iterator
|
|
||||||
inline void setEnd();
|
|
||||||
|
|
||||||
//- Set edgeID_ to be the other edge on the face that uses the
|
|
||||||
// point.
|
|
||||||
inline void otherEdge(const label cellI);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Constructors
|
|
||||||
|
|
||||||
//- Construct from components
|
|
||||||
inline patchPointEdgeCirculator
|
|
||||||
(
|
|
||||||
const primitiveFacePatch&,
|
|
||||||
const PackedBoolList& nonManifoldEdge,
|
|
||||||
const label edgeID,
|
|
||||||
const label index,
|
|
||||||
const label pointID
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Construct as copy
|
|
||||||
inline patchPointEdgeCirculator(const patchPointEdgeCirculator&);
|
|
||||||
|
|
||||||
|
|
||||||
// Member Functions
|
|
||||||
|
|
||||||
inline label edgeID() const;
|
|
||||||
|
|
||||||
inline label index() const;
|
|
||||||
|
|
||||||
inline label pointID() const;
|
|
||||||
|
|
||||||
//- Helper: get face according to the index.
|
|
||||||
// Returns -1 if on end.
|
|
||||||
inline label faceID() const;
|
|
||||||
|
|
||||||
//- Walk back until non-manifold edge (if any) or minimum edge.
|
|
||||||
inline void setCanonical();
|
|
||||||
|
|
||||||
|
|
||||||
// Member Operators
|
|
||||||
|
|
||||||
inline void operator=(const patchPointEdgeCirculator& iter);
|
|
||||||
|
|
||||||
inline bool operator==(const patchPointEdgeCirculator& iter) const;
|
|
||||||
|
|
||||||
inline bool operator!=(const patchPointEdgeCirculator& iter) const;
|
|
||||||
|
|
||||||
//- Step to next face.
|
|
||||||
inline patchPointEdgeCirculator& operator++();
|
|
||||||
|
|
||||||
//- iterator set to the beginning face. For internal edges this is
|
|
||||||
// the current face. For boundary edges this is the first boundary face
|
|
||||||
// reached from walking back (i.e. in opposite direction to ++)
|
|
||||||
inline patchPointEdgeCirculator begin() const;
|
|
||||||
inline patchPointEdgeCirculator cbegin() const;
|
|
||||||
|
|
||||||
//- iterator set to beyond the end of the walk.
|
|
||||||
inline const patchPointEdgeCirculator& end() const;
|
|
||||||
inline const patchPointEdgeCirculator& cend() const;
|
|
||||||
|
|
||||||
// Info
|
|
||||||
|
|
||||||
//- Return info proxy.
|
|
||||||
// Used to print token information to a stream
|
|
||||||
InfoProxy<patchPointEdgeCirculator> info() const
|
|
||||||
{
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Ostream& operator<<
|
|
||||||
(
|
|
||||||
Ostream&,
|
|
||||||
const InfoProxy<patchPointEdgeCirculator>&
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ostream& operator<<(Ostream&, const InfoProxy<patchPointEdgeCirculator>&);
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
} // End namespace Foam
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
#include "patchPointEdgeCirculatorI.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -1,308 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / 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/>.
|
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
||||||
|
|
||||||
void Foam::patchPointEdgeCirculator::setEnd()
|
|
||||||
{
|
|
||||||
edgeID_ = -1;
|
|
||||||
pointID_ = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Cross face to other edge on point
|
|
||||||
void Foam::patchPointEdgeCirculator::otherEdge(const label faceI)
|
|
||||||
{
|
|
||||||
const labelList& fEdges = patch_.faceEdges()[faceI];
|
|
||||||
const face& f = patch_.localFaces()[faceI];
|
|
||||||
label fp = findIndex(f, pointID_);
|
|
||||||
|
|
||||||
if (fEdges[fp] == edgeID_)
|
|
||||||
{
|
|
||||||
edgeID_ = fEdges[f.rcIndex(fp)];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check for now
|
|
||||||
if (fEdges[f.rcIndex(fp)] != edgeID_)
|
|
||||||
{
|
|
||||||
FatalErrorIn("patchPointEdgeCirculator::otherEdge(const label)")
|
|
||||||
<< "face:" << faceI
|
|
||||||
<< " verts:" << f
|
|
||||||
<< " edges:" << fEdges
|
|
||||||
<< " looking for other edge than " << edgeID_
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
edgeID_ = fEdges[fp];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
//- Construct from components
|
|
||||||
Foam::patchPointEdgeCirculator::patchPointEdgeCirculator
|
|
||||||
(
|
|
||||||
const primitiveFacePatch& patch,
|
|
||||||
const PackedBoolList& nonManifoldEdge,
|
|
||||||
const label edgeID,
|
|
||||||
const label index,
|
|
||||||
|
|
||||||
const label pointID
|
|
||||||
)
|
|
||||||
:
|
|
||||||
patch_(patch),
|
|
||||||
nonManifoldEdge_(nonManifoldEdge),
|
|
||||||
edgeID_(edgeID),
|
|
||||||
index_(index),
|
|
||||||
pointID_(pointID),
|
|
||||||
startEdgeID_(edgeID_)
|
|
||||||
{
|
|
||||||
if (edgeID_ != -1)
|
|
||||||
{
|
|
||||||
const edge& e = patch_.edges()[edgeID_];
|
|
||||||
|
|
||||||
if (pointID_ != e[0] && pointID_ != e[1])
|
|
||||||
{
|
|
||||||
FatalErrorIn
|
|
||||||
(
|
|
||||||
"patchPointEdgeCirculator::patchPointEdgeCirculator(..)"
|
|
||||||
) << "edge " << edgeID_ << " verts " << e
|
|
||||||
<< " does not contain point " << pointID_ << abort(FatalError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//- Construct copy
|
|
||||||
Foam::patchPointEdgeCirculator::patchPointEdgeCirculator
|
|
||||||
(
|
|
||||||
const patchPointEdgeCirculator& circ
|
|
||||||
)
|
|
||||||
:
|
|
||||||
patch_(circ.patch_),
|
|
||||||
nonManifoldEdge_(circ.nonManifoldEdge_),
|
|
||||||
edgeID_(circ.edgeID_),
|
|
||||||
index_(circ.index_),
|
|
||||||
pointID_(circ.pointID_),
|
|
||||||
startEdgeID_(circ.startEdgeID_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
Foam::label Foam::patchPointEdgeCirculator::edgeID() const
|
|
||||||
{
|
|
||||||
return edgeID_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::label Foam::patchPointEdgeCirculator::index() const
|
|
||||||
{
|
|
||||||
return index_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::label Foam::patchPointEdgeCirculator::pointID() const
|
|
||||||
{
|
|
||||||
return pointID_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::label Foam::patchPointEdgeCirculator::faceID() const
|
|
||||||
{
|
|
||||||
if (edgeID_ != -1 && index_ != -1)
|
|
||||||
{
|
|
||||||
return patch_.edgeFaces()[edgeID_][index_];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::patchPointEdgeCirculator::operator=
|
|
||||||
(
|
|
||||||
const patchPointEdgeCirculator& circ
|
|
||||||
)
|
|
||||||
{
|
|
||||||
edgeID_ = circ.edgeID_;
|
|
||||||
index_ = circ.index_;
|
|
||||||
pointID_ = circ.pointID_;
|
|
||||||
startEdgeID_ = circ.startEdgeID_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Foam::patchPointEdgeCirculator::operator==
|
|
||||||
(
|
|
||||||
const patchPointEdgeCirculator& circ
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
// Do just enough to have setEnd() produce an iterator equal to end().
|
|
||||||
// Could include the direction(i.e. index_) to make sure that two
|
|
||||||
// circulators around same point but in different direction are not equal.
|
|
||||||
return edgeID_ == circ.edgeID_ && pointID_ == circ.pointID_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Foam::patchPointEdgeCirculator::operator!=
|
|
||||||
(
|
|
||||||
const patchPointEdgeCirculator& circ
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
return !(*this == circ);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::patchPointEdgeCirculator::setCanonical()
|
|
||||||
{
|
|
||||||
if (edgeID_ == -1)
|
|
||||||
{
|
|
||||||
FatalErrorIn("patchPointEdgeCirculator::setCanonical()")
|
|
||||||
<< "Already reached end(). Cannot walk any further."
|
|
||||||
<< abort(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
label minEdgeID = edgeID_;
|
|
||||||
label minIndex = index_;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (nonManifoldEdge_[edgeID_])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step back
|
|
||||||
const labelList& eFaces = patch_.edgeFaces()[edgeID_];
|
|
||||||
|
|
||||||
if (eFaces.size() != 2)
|
|
||||||
{
|
|
||||||
FatalErrorIn("patchPointEdgeCirculator::setCanonical()")
|
|
||||||
<< "problem eFaces:" << eFaces << abort(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
label faceI = (index_ == 0 ? eFaces[1] : eFaces[0]);
|
|
||||||
|
|
||||||
// Step to other edge on face
|
|
||||||
otherEdge(faceI);
|
|
||||||
|
|
||||||
// Update index
|
|
||||||
index_ = findIndex(patch_.edgeFaces()[edgeID_], faceI);
|
|
||||||
|
|
||||||
if (edgeID_ < minEdgeID)
|
|
||||||
{
|
|
||||||
minEdgeID = edgeID_;
|
|
||||||
minIndex = index_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (edgeID_ == startEdgeID_)
|
|
||||||
{
|
|
||||||
edgeID_ = minEdgeID;
|
|
||||||
index_ = minIndex;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startEdgeID_ = edgeID_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//- Step to next edge.
|
|
||||||
Foam::patchPointEdgeCirculator&
|
|
||||||
Foam::patchPointEdgeCirculator::operator++()
|
|
||||||
{
|
|
||||||
if (index_ == -1)
|
|
||||||
{
|
|
||||||
setEnd();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Step to other edge on face
|
|
||||||
label faceI = patch_.edgeFaces()[edgeID_][index_];
|
|
||||||
otherEdge(faceI);
|
|
||||||
|
|
||||||
if (edgeID_ == startEdgeID_)
|
|
||||||
{
|
|
||||||
setEnd();
|
|
||||||
}
|
|
||||||
else if (nonManifoldEdge_[edgeID_])
|
|
||||||
{
|
|
||||||
// Reached non-manifold edge. Cannot walk further.
|
|
||||||
// Mark so it gets set to end next time.
|
|
||||||
index_ = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const labelList& eFaces = patch_.edgeFaces()[edgeID_];
|
|
||||||
|
|
||||||
if (eFaces.size() != 2)
|
|
||||||
{
|
|
||||||
FatalErrorIn("patchPointEdgeCirculator:::operator++()")
|
|
||||||
<< "problem eFaces:" << eFaces << abort(FatalError);
|
|
||||||
}
|
|
||||||
// Point to the face that is not faceI
|
|
||||||
index_ = (eFaces[0] != faceI ? 0 : 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::patchPointEdgeCirculator Foam::patchPointEdgeCirculator::begin() const
|
|
||||||
{
|
|
||||||
patchPointEdgeCirculator iter(*this);
|
|
||||||
iter.setCanonical();
|
|
||||||
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Foam::patchPointEdgeCirculator Foam::patchPointEdgeCirculator::cbegin() const
|
|
||||||
{
|
|
||||||
patchPointEdgeCirculator iter(*this);
|
|
||||||
iter.setCanonical();
|
|
||||||
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Foam::patchPointEdgeCirculator& Foam::patchPointEdgeCirculator::end()
|
|
||||||
const
|
|
||||||
{
|
|
||||||
return endConstIter;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Foam::patchPointEdgeCirculator& Foam::patchPointEdgeCirculator::cend()
|
|
||||||
const
|
|
||||||
{
|
|
||||||
return endConstIter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
Reference in New Issue
Block a user