mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
fixed layer addition iterations
This commit is contained in:
@ -274,6 +274,14 @@ addLayersControls
|
|||||||
|
|
||||||
// Create buffer region for new layer terminations
|
// Create buffer region for new layer terminations
|
||||||
nBufferCellsNoExtrude 0;
|
nBufferCellsNoExtrude 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Overall max number of layer addition iterations
|
||||||
|
nLayerIter 50;
|
||||||
|
|
||||||
|
// Max number of iterations after which relaxed meshQuality controls
|
||||||
|
// get used.
|
||||||
|
nRelaxedIter 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -335,6 +343,16 @@ meshQualityControls
|
|||||||
nSmoothScale 4;
|
nSmoothScale 4;
|
||||||
//- amount to scale back displacement at error points
|
//- amount to scale back displacement at error points
|
||||||
errorReduction 0.75;
|
errorReduction 0.75;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Optional : some meshing phases allow usage of relaxed rules.
|
||||||
|
// See e.g. addLayersControls::nRelaxedIter.
|
||||||
|
relaxed
|
||||||
|
{
|
||||||
|
//- Maximum non-orthogonality allowed. Set to 180 to disable.
|
||||||
|
maxNonOrtho 75;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2292,7 +2292,7 @@ bool Foam::autoLayerDriver::cellsUseFace
|
|||||||
Foam::label Foam::autoLayerDriver::checkAndUnmark
|
Foam::label Foam::autoLayerDriver::checkAndUnmark
|
||||||
(
|
(
|
||||||
const addPatchCellLayer& addLayer,
|
const addPatchCellLayer& addLayer,
|
||||||
const dictionary& motionDict,
|
const dictionary& meshQualityDict,
|
||||||
const indirectPrimitivePatch& pp,
|
const indirectPrimitivePatch& pp,
|
||||||
const fvMesh& newMesh,
|
const fvMesh& newMesh,
|
||||||
|
|
||||||
@ -2304,7 +2304,7 @@ Foam::label Foam::autoLayerDriver::checkAndUnmark
|
|||||||
// Check the resulting mesh for errors
|
// Check the resulting mesh for errors
|
||||||
Info<< nl << "Checking mesh with layer ..." << endl;
|
Info<< nl << "Checking mesh with layer ..." << endl;
|
||||||
faceSet wrongFaces(newMesh, "wrongFaces", newMesh.nFaces()/1000);
|
faceSet wrongFaces(newMesh, "wrongFaces", newMesh.nFaces()/1000);
|
||||||
motionSmoother::checkMesh(false, newMesh, motionDict, wrongFaces);
|
motionSmoother::checkMesh(false, newMesh, meshQualityDict, wrongFaces);
|
||||||
Info<< "Detected " << returnReduce(wrongFaces.size(), sumOp<label>())
|
Info<< "Detected " << returnReduce(wrongFaces.size(), sumOp<label>())
|
||||||
<< " illegal faces"
|
<< " illegal faces"
|
||||||
<< " (concave, zero area or negative cell pyramid volume)"
|
<< " (concave, zero area or negative cell pyramid volume)"
|
||||||
@ -2709,7 +2709,7 @@ void Foam::autoLayerDriver::addLayers
|
|||||||
boolList flaggedCells;
|
boolList flaggedCells;
|
||||||
boolList flaggedFaces;
|
boolList flaggedFaces;
|
||||||
|
|
||||||
while (true)
|
for (label iter = 0; iter < layerParams.nLayerIter(); iter++)
|
||||||
{
|
{
|
||||||
// Make sure displacement is equal on both sides of coupled patches.
|
// Make sure displacement is equal on both sides of coupled patches.
|
||||||
syncPatchDisplacement
|
syncPatchDisplacement
|
||||||
@ -2951,10 +2951,17 @@ void Foam::autoLayerDriver::addLayers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unset the extrusion at the pp.
|
// Unset the extrusion at the pp.
|
||||||
|
const dictionary& meshQualityDict =
|
||||||
|
(
|
||||||
|
iter < layerParams.nRelaxedIter()
|
||||||
|
? motionDict
|
||||||
|
: motionDict.subDict("relaxed")
|
||||||
|
);
|
||||||
|
|
||||||
label nTotChanged = checkAndUnmark
|
label nTotChanged = checkAndUnmark
|
||||||
(
|
(
|
||||||
addLayer,
|
addLayer,
|
||||||
motionDict,
|
meshQualityDict,
|
||||||
pp,
|
pp,
|
||||||
newMesh,
|
newMesh,
|
||||||
|
|
||||||
|
|||||||
@ -211,8 +211,24 @@ Foam::layerParameters::layerParameters
|
|||||||
(
|
(
|
||||||
readLabel(dict.lookup("nBufferCellsNoExtrude"))
|
readLabel(dict.lookup("nBufferCellsNoExtrude"))
|
||||||
),
|
),
|
||||||
nSnap_(readLabel(dict.lookup("nSnap")))
|
nSnap_(readLabel(dict.lookup("nSnap"))),
|
||||||
{}
|
nLayerIter_(readLabel(dict.lookup("nLayerIter"))),
|
||||||
|
nRelaxedIter_(labelMax)
|
||||||
|
{
|
||||||
|
if (dict.found("nRelaxedIter"))
|
||||||
|
{
|
||||||
|
dict.lookup("nRelaxedIter") >> nRelaxedIter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nLayerIter_ < 0 || nRelaxedIter_ < 0)
|
||||||
|
{
|
||||||
|
FatalErrorIn("layerParameters::layerParameters(..)")
|
||||||
|
<< "Layer iterations should be >= 0." << endl
|
||||||
|
<< "nLayerIter:" << nLayerIter_
|
||||||
|
<< " nRelaxedIter:" << nRelaxedIter_
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Construct from dictionary
|
// Construct from dictionary
|
||||||
@ -276,8 +292,24 @@ Foam::layerParameters::layerParameters
|
|||||||
(
|
(
|
||||||
readLabel(dict.lookup("nBufferCellsNoExtrude"))
|
readLabel(dict.lookup("nBufferCellsNoExtrude"))
|
||||||
),
|
),
|
||||||
nSnap_(readLabel(dict.lookup("nRelaxIter")))
|
nSnap_(readLabel(dict.lookup("nRelaxIter"))),
|
||||||
|
nLayerIter_(readLabel(dict.lookup("nLayerIter"))),
|
||||||
|
nRelaxedIter_(labelMax)
|
||||||
{
|
{
|
||||||
|
if (dict.found("nRelaxedIter"))
|
||||||
|
{
|
||||||
|
dict.lookup("nRelaxedIter") >> nRelaxedIter_;
|
||||||
|
}
|
||||||
|
if (nLayerIter_ < 0 || nRelaxedIter_ < 0)
|
||||||
|
{
|
||||||
|
FatalErrorIn("layerParameters::layerParameters(..)")
|
||||||
|
<< "Layer iterations should be >= 0." << endl
|
||||||
|
<< "nLayerIter:" << nLayerIter_
|
||||||
|
<< " nRelaxedIter:" << nRelaxedIter_
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const dictionary& layersDict = dict.subDict("layers");
|
const dictionary& layersDict = dict.subDict("layers");
|
||||||
|
|
||||||
forAll(boundaryMesh, patchI)
|
forAll(boundaryMesh, patchI)
|
||||||
|
|||||||
@ -105,6 +105,10 @@ class layerParameters
|
|||||||
|
|
||||||
label nSnap_;
|
label nSnap_;
|
||||||
|
|
||||||
|
label nLayerIter_;
|
||||||
|
|
||||||
|
label nRelaxedIter_;
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
@ -196,26 +200,20 @@ public:
|
|||||||
return nGrow_;
|
return nGrow_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of smoothing iterations of surface normals
|
//- Number of smoothing iterations of surface normals
|
||||||
label nSmoothSurfaceNormals() const
|
label nSmoothSurfaceNormals() const
|
||||||
{
|
{
|
||||||
return nSmoothSurfaceNormals_;
|
return nSmoothSurfaceNormals_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of smoothing iterations of interior mesh movement
|
//- Number of smoothing iterations of interior mesh movement
|
||||||
// direction
|
// direction
|
||||||
label nSmoothNormals() const
|
label nSmoothNormals() const
|
||||||
{
|
{
|
||||||
return nSmoothNormals_;
|
return nSmoothNormals_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Smooth layer thickness over surface patches
|
//- Stop layer growth on highly warped cells
|
||||||
label nSmoothThickness() const
|
|
||||||
{
|
|
||||||
return nSmoothThickness_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop layer growth on highly warped cells
|
|
||||||
scalar maxFaceThicknessRatio() const
|
scalar maxFaceThicknessRatio() const
|
||||||
{
|
{
|
||||||
return maxFaceThicknessRatio_;
|
return maxFaceThicknessRatio_;
|
||||||
@ -226,20 +224,26 @@ public:
|
|||||||
return layerTerminationCos_;
|
return layerTerminationCos_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce layer growth where ratio thickness to medial
|
//- Smooth layer thickness over surface patches
|
||||||
// distance is large
|
label nSmoothThickness() const
|
||||||
|
{
|
||||||
|
return nSmoothThickness_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Reduce layer growth where ratio thickness to medial
|
||||||
|
// distance is large
|
||||||
scalar maxThicknessToMedialRatio() const
|
scalar maxThicknessToMedialRatio() const
|
||||||
{
|
{
|
||||||
return maxThicknessToMedialRatio_;
|
return maxThicknessToMedialRatio_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Angle used to pick up medial axis points
|
//- Angle used to pick up medial axis points
|
||||||
scalar minMedianAxisAngleCos() const
|
scalar minMedianAxisAngleCos() const
|
||||||
{
|
{
|
||||||
return minMedianAxisAngleCos_;
|
return minMedianAxisAngleCos_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create buffer region for new layer terminations
|
//- Create buffer region for new layer terminations
|
||||||
label nBufferCellsNoExtrude() const
|
label nBufferCellsNoExtrude() const
|
||||||
{
|
{
|
||||||
return nBufferCellsNoExtrude_;
|
return nBufferCellsNoExtrude_;
|
||||||
@ -249,6 +253,24 @@ public:
|
|||||||
{
|
{
|
||||||
return nSnap_;
|
return nSnap_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overall
|
||||||
|
|
||||||
|
//- Number of overall layer addition iterations
|
||||||
|
label nLayerIter() const
|
||||||
|
{
|
||||||
|
return nLayerIter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Number of iterations after which relaxed motion rules
|
||||||
|
// are to be used.
|
||||||
|
label nRelaxedIter() const
|
||||||
|
{
|
||||||
|
return nRelaxedIter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -825,6 +825,28 @@ bool Foam::motionSmoother::scaleMesh
|
|||||||
const bool smoothMesh,
|
const bool smoothMesh,
|
||||||
const label nAllowableErrors
|
const label nAllowableErrors
|
||||||
)
|
)
|
||||||
|
{
|
||||||
|
return scaleMesh
|
||||||
|
(
|
||||||
|
checkFaces,
|
||||||
|
baffles,
|
||||||
|
paramDict_,
|
||||||
|
paramDict_,
|
||||||
|
smoothMesh,
|
||||||
|
nAllowableErrors
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::motionSmoother::scaleMesh
|
||||||
|
(
|
||||||
|
labelList& checkFaces,
|
||||||
|
const List<labelPair>& baffles,
|
||||||
|
const dictionary& paramDict,
|
||||||
|
const dictionary& meshQualityDict,
|
||||||
|
const bool smoothMesh,
|
||||||
|
const label nAllowableErrors
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (!smoothMesh && adaptPatchIDs_.empty())
|
if (!smoothMesh && adaptPatchIDs_.empty())
|
||||||
{
|
{
|
||||||
@ -859,9 +881,9 @@ bool Foam::motionSmoother::scaleMesh
|
|||||||
}
|
}
|
||||||
|
|
||||||
const scalar errorReduction =
|
const scalar errorReduction =
|
||||||
readScalar(paramDict_.lookup("errorReduction"));
|
readScalar(paramDict.lookup("errorReduction"));
|
||||||
const label nSmoothScale =
|
const label nSmoothScale =
|
||||||
readLabel(paramDict_.lookup("nSmoothScale"));
|
readLabel(paramDict.lookup("nSmoothScale"));
|
||||||
|
|
||||||
|
|
||||||
// Note: displacement_ should already be synced already from setDisplacement
|
// Note: displacement_ should already be synced already from setDisplacement
|
||||||
@ -921,7 +943,7 @@ bool Foam::motionSmoother::scaleMesh
|
|||||||
|
|
||||||
// Check. Returns parallel number of incorrect faces.
|
// Check. Returns parallel number of incorrect faces.
|
||||||
faceSet wrongFaces(mesh_, "wrongFaces", mesh_.nFaces()/100+100);
|
faceSet wrongFaces(mesh_, "wrongFaces", mesh_.nFaces()/100+100);
|
||||||
checkMesh(false, mesh_, paramDict_, checkFaces, baffles, wrongFaces);
|
checkMesh(false, mesh_, meshQualityDict, checkFaces, baffles, wrongFaces);
|
||||||
|
|
||||||
if (returnReduce(wrongFaces.size(), sumOp<label>()) <= nAllowableErrors)
|
if (returnReduce(wrongFaces.size(), sumOp<label>()) <= nAllowableErrors)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -52,7 +52,7 @@ Description
|
|||||||
@endverbatim
|
@endverbatim
|
||||||
|
|
||||||
Note
|
Note
|
||||||
Shared points (parallel): a processor can have points which are part of
|
- Shared points (parallel): a processor can have points which are part of
|
||||||
pp on another processor but have no pp itself (i.e. it has points
|
pp on another processor but have no pp itself (i.e. it has points
|
||||||
and/or edges but no faces of pp). Hence we have to be careful when e.g.
|
and/or edges but no faces of pp). Hence we have to be careful when e.g.
|
||||||
synchronising displacements that the value from the processor which has
|
synchronising displacements that the value from the processor which has
|
||||||
@ -61,10 +61,13 @@ Note
|
|||||||
else. The combine operator used will give preference to non-zero
|
else. The combine operator used will give preference to non-zero
|
||||||
values.
|
values.
|
||||||
|
|
||||||
Various routines take baffles. These are sets of boundary faces that
|
- Various routines take baffles. These are sets of boundary faces that
|
||||||
are treated as a single internal face. This is a hack used to apply
|
are treated as a single internal face. This is a hack used to apply
|
||||||
movement to internal faces.
|
movement to internal faces.
|
||||||
|
|
||||||
|
- Mesh constraints are looked up from the supplied dictionary. (uses
|
||||||
|
recursive lookup)
|
||||||
|
|
||||||
SourceFiles
|
SourceFiles
|
||||||
motionSmoother.C
|
motionSmoother.C
|
||||||
motionSmootherTemplates.C
|
motionSmootherTemplates.C
|
||||||
@ -395,6 +398,17 @@ public:
|
|||||||
const label nAllow = 0
|
const label nAllow = 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//- Move mesh with externally provided mesh constraints
|
||||||
|
bool scaleMesh
|
||||||
|
(
|
||||||
|
labelList& checkFaces,
|
||||||
|
const List<labelPair>& baffles,
|
||||||
|
const dictionary& paramDict,
|
||||||
|
const dictionary& meshQualityDict,
|
||||||
|
const bool smoothMesh = true,
|
||||||
|
const label nAllow = 0
|
||||||
|
);
|
||||||
|
|
||||||
//- Update topology
|
//- Update topology
|
||||||
void updateMesh();
|
void updateMesh();
|
||||||
|
|
||||||
|
|||||||
@ -28,19 +28,6 @@ License
|
|||||||
#include "polyMeshGeometry.H"
|
#include "polyMeshGeometry.H"
|
||||||
#include "IOmanip.H"
|
#include "IOmanip.H"
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
bool Foam::motionSmoother::checkMesh
|
bool Foam::motionSmoother::checkMesh
|
||||||
@ -74,17 +61,50 @@ bool Foam::motionSmoother::checkMesh
|
|||||||
labelHashSet& wrongFaces
|
labelHashSet& wrongFaces
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const scalar maxNonOrtho(readScalar(dict.lookup("maxNonOrtho")));
|
const scalar maxNonOrtho
|
||||||
const scalar minVol(readScalar(dict.lookup("minVol")));
|
(
|
||||||
const scalar maxConcave(readScalar(dict.lookup("maxConcave")));
|
readScalar(dict.lookup("maxNonOrtho", true))
|
||||||
const scalar minArea(readScalar(dict.lookup("minArea")));
|
);
|
||||||
const scalar maxIntSkew(readScalar(dict.lookup("maxInternalSkewness")));
|
const scalar minVol
|
||||||
const scalar maxBounSkew(readScalar(dict.lookup("maxBoundarySkewness")));
|
(
|
||||||
const scalar minWeight(readScalar(dict.lookup("minFaceWeight")));
|
readScalar(dict.lookup("minVol", true))
|
||||||
const scalar minVolRatio(readScalar(dict.lookup("minVolRatio")));
|
);
|
||||||
const scalar minTwist(readScalar(dict.lookup("minTwist")));
|
const scalar maxConcave
|
||||||
const scalar minTriangleTwist(readScalar(dict.lookup("minTriangleTwist")));
|
(
|
||||||
const scalar minDet(readScalar(dict.lookup("minDeterminant")));
|
readScalar(dict.lookup("maxConcave", true))
|
||||||
|
);
|
||||||
|
const scalar minArea
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minArea", true))
|
||||||
|
);
|
||||||
|
const scalar maxIntSkew
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("maxInternalSkewness", true))
|
||||||
|
);
|
||||||
|
const scalar maxBounSkew
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("maxBoundarySkewness", true))
|
||||||
|
);
|
||||||
|
const scalar minWeight
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minFaceWeight", true))
|
||||||
|
);
|
||||||
|
const scalar minVolRatio
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minVolRatio", true))
|
||||||
|
);
|
||||||
|
const scalar minTwist
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minTwist", true))
|
||||||
|
);
|
||||||
|
const scalar minTriangleTwist
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minTriangleTwist", true))
|
||||||
|
);
|
||||||
|
const scalar minDet
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minDeterminant", true))
|
||||||
|
);
|
||||||
|
|
||||||
label nWrongFaces = 0;
|
label nWrongFaces = 0;
|
||||||
|
|
||||||
@ -389,17 +409,50 @@ bool Foam::motionSmoother::checkMesh
|
|||||||
labelHashSet& wrongFaces
|
labelHashSet& wrongFaces
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const scalar maxNonOrtho(readScalar(dict.lookup("maxNonOrtho")));
|
const scalar maxNonOrtho
|
||||||
const scalar minVol(readScalar(dict.lookup("minVol")));
|
(
|
||||||
const scalar maxConcave(readScalar(dict.lookup("maxConcave")));
|
readScalar(dict.lookup("maxNonOrtho", true))
|
||||||
const scalar minArea(readScalar(dict.lookup("minArea")));
|
);
|
||||||
const scalar maxIntSkew(readScalar(dict.lookup("maxInternalSkewness")));
|
const scalar minVol
|
||||||
const scalar maxBounSkew(readScalar(dict.lookup("maxBoundarySkewness")));
|
(
|
||||||
const scalar minWeight(readScalar(dict.lookup("minFaceWeight")));
|
readScalar(dict.lookup("minVol", true))
|
||||||
const scalar minVolRatio(readScalar(dict.lookup("minVolRatio")));
|
);
|
||||||
const scalar minTwist(readScalar(dict.lookup("minTwist")));
|
const scalar maxConcave
|
||||||
const scalar minTriangleTwist(readScalar(dict.lookup("minTriangleTwist")));
|
(
|
||||||
const scalar minDet(readScalar(dict.lookup("minDeterminant")));
|
readScalar(dict.lookup("maxConcave", true))
|
||||||
|
);
|
||||||
|
const scalar minArea
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minArea", true))
|
||||||
|
);
|
||||||
|
const scalar maxIntSkew
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("maxInternalSkewness", true))
|
||||||
|
);
|
||||||
|
const scalar maxBounSkew
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("maxBoundarySkewness", true))
|
||||||
|
);
|
||||||
|
const scalar minWeight
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minFaceWeight", true))
|
||||||
|
);
|
||||||
|
const scalar minVolRatio
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minVolRatio", true))
|
||||||
|
);
|
||||||
|
const scalar minTwist
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minTwist", true))
|
||||||
|
);
|
||||||
|
const scalar minTriangleTwist
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minTriangleTwist", true))
|
||||||
|
);
|
||||||
|
const scalar minDet
|
||||||
|
(
|
||||||
|
readScalar(dict.lookup("minDeterminant", true))
|
||||||
|
);
|
||||||
|
|
||||||
label nWrongFaces = 0;
|
label nWrongFaces = 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user