Adding faceCollapseMode enum to control mode. Fixing logic error,

returning validCollapse as the status of the faceCollapse was wrong,
it didn't necessarily mean the face was collapsed.

Adding mpre filtering controls to cvContol and using them in the
filtering functions.

Removing minimumEdgeLength(const point& pt) - not needed, always using
the stored vertex size.
This commit is contained in:
graham
2010-01-08 16:40:04 +00:00
parent 7800ceac99
commit d598afbd90
7 changed files with 233 additions and 178 deletions

View File

@ -93,6 +93,15 @@ public:
rmFine // Rebuild the conformation with fine tolerances (slower) rmFine // Rebuild the conformation with fine tolerances (slower)
}; };
enum faceCollapseMode
{
fcmNone, // Do not collapse face
fcmEdge, // Collapse face to a single edge
fcmPoint, // Collapse face to a point
fcmDeferredMultiEdge // Collapse face to several edges
};
private: private:
// Private data // Private data
@ -214,9 +223,6 @@ private:
//- Return the local maximum surface protrusion distance //- Return the local maximum surface protrusion distance
inline scalar maxSurfaceProtrusion(const point& pt) const; inline scalar maxSurfaceProtrusion(const point& pt) const;
//- Return the local minimum allowed dual edge length
inline scalar minimumEdgeLength(const point& pt) const;
//- Return the required alignment directions at the given location //- Return the required alignment directions at the given location
tensor requiredAlignment(const point& pt) const; tensor requiredAlignment(const point& pt) const;
@ -504,7 +510,7 @@ private:
//- Collapse a face to an edge, updating the point and point //- Collapse a face to an edge, updating the point and point
//- map. Returns a bool of success or failure. //- map. Returns a bool of success or failure.
bool collapseFaceToEdge bool collapseFace
( (
const face& f, const face& f,
pointField& pts, pointField& pts,

View File

@ -76,8 +76,6 @@ void Foam::conformalVoronoiMesh::calcDualMesh
} }
} }
// Dual face filtering
// Indexing Delaunay cells, which are the dual vertices // Indexing Delaunay cells, which are the dual vertices
label dualVertI = 0; label dualVertI = 0;
@ -386,7 +384,7 @@ Foam::label Foam::conformalVoronoiMesh::mergeCloseDualVertices
{ {
label nPtsMerged = 0; label nPtsMerged = 0;
scalar closenessTolerance = 1e-6; scalar closenessTolerance = cvMeshControls().mergeClosenessCoeff();
for for
( (
@ -512,7 +510,10 @@ Foam::label Foam::conformalVoronoiMesh::smoothSurfaceDualFaces
{ {
label nCollapsedFaces = 0; label nCollapsedFaces = 0;
const scalar cosPerpendicularToleranceAngle = cos(degToRad(80)); const scalar cosPerpendicularToleranceAngle = cos
(
degToRad(cvMeshControls().surfaceStepFaceAngle())
);
for for
( (
@ -579,7 +580,16 @@ Foam::label Foam::conformalVoronoiMesh::smoothSurfaceDualFaces
vector faceNormal = dualFace.normal(pts); vector faceNormal = dualFace.normal(pts);
if (mag(faceNormal) < VSMALL)
{
// If the face is essentially zero area, then force it
// to be collapsed by making the dot product result -1
faceNormal = -surfaceNormal;
}
else
{
faceNormal /= mag(faceNormal); faceNormal /= mag(faceNormal);
}
if ((faceNormal & surfaceNormal) < cosPerpendicularToleranceAngle) if ((faceNormal & surfaceNormal) < cosPerpendicularToleranceAngle)
{ {
@ -591,7 +601,7 @@ Foam::label Foam::conformalVoronoiMesh::smoothSurfaceDualFaces
if if
( (
collapseFaceToEdge collapseFace
( (
dualFace, dualFace,
pts, pts,
@ -642,7 +652,7 @@ Foam::label Foam::conformalVoronoiMesh::collapseFaces
{ {
label nCollapsedFaces = 0; label nCollapsedFaces = 0;
scalar collapseSizeLimitCoeff = cvMeshControls().minimumEdgeLengthCoeff(); scalar collapseSizeLimitCoeff = cvMeshControls().filterSizeCoeff();
for for
( (
@ -687,7 +697,7 @@ Foam::label Foam::conformalVoronoiMesh::collapseFaces
if if
( (
collapseFaceToEdge collapseFace
( (
dualFace, dualFace,
pts, pts,
@ -706,7 +716,7 @@ Foam::label Foam::conformalVoronoiMesh::collapseFaces
} }
bool Foam::conformalVoronoiMesh::collapseFaceToEdge bool Foam::conformalVoronoiMesh::collapseFace
( (
const face& f, const face& f,
pointField& pts, pointField& pts,
@ -715,7 +725,7 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
scalar collapseSizeLimitCoeff scalar collapseSizeLimitCoeff
) const ) const
{ {
scalar guardFraction = 0.3; bool limitToQuadsOrTris = true;
const vector fC = f.centre(pts); const vector fC = f.centre(pts);
@ -730,58 +740,28 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
// eigenvector corresponding to the smaller of the two remaining // eigenvector corresponding to the smaller of the two remaining
// eigenvalues is the dominant axis in a high aspect ratio face. // eigenvalues is the dominant axis in a high aspect ratio face.
// Normalise inertia tensor to remove problems with small values
scalar magJ = mag(J); scalar magJ = mag(J);
scalar detJ = SMALL;
if (magJ > VSMALL) if (magJ > VSMALL)
{ {
// Normalise inertia tensor to remove problems with small values
J /= mag(J); J /= mag(J);
// J /= cmptMax(J); // J /= cmptMax(J);
// J /= max(eigenValues(J).x(), SMALL); // J /= max(eigenValues(J).x(), SMALL);
}
else
{
WarningIn
(
"Foam::conformalVoronoiMesh::collapseFaceToEdge"
"("
"const face& f,"
"pointField& pts,"
"Map<label>& dualPtIndexMap"
") const"
)
<< "Inertia tensor magnitude too small, not collapsing." << nl
<< J << nl << "mag = " << magJ
<< endl;
// Output face and collapse axis for visualisation // Calculating determinant, including stabilisation for zero or
// small negative values
forAll(f, fPtI) detJ = max(det(J), SMALL);
{
meshTools::writeOBJ(Info, pts[f[fPtI]]);
}
Info<< "f";
forAll(f, fPtI)
{
Info << " " << fPtI + 1;
}
Info<< nl << endl;
return false;
} }
vector collapseAxis = vector::zero; vector collapseAxis = vector::zero;
scalar aspectRatio = 1; scalar aspectRatio = 1;
// Calculating determinant, including stabilisation for zero or
// small negative values
scalar detJ = max(det(J), SMALL);
if (detJ < 1e-5) if (detJ < 1e-5)
{ {
const edgeList& eds = f.edges(); const edgeList& eds = f.edges();
@ -839,7 +819,7 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
{ {
WarningIn WarningIn
( (
"Foam::conformalVoronoiMesh::collapseFaceToEdge" "Foam::conformalVoronoiMesh::collapseFace"
"(" "("
"const face& f," "const face& f,"
"pointField& pts," "pointField& pts,"
@ -849,33 +829,6 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
<< "No collapse axis found for face, not collapsing." << "No collapse axis found for face, not collapsing."
<< endl; << endl;
// // Output face and collapse axis for visualisation
// Info<< nl << "# Aspect ratio = " << aspectRatio << nl
// << "# collapseAxis = " << collapseAxis << nl
// << "# eigenvalues = " << eVals << endl;
// scalar scale = 2.0*mag(fC - pts[f[0]]);
// meshTools::writeOBJ(Info, fC);
// meshTools::writeOBJ(Info, fC + scale*collapseAxis);
// Info<< "f 1 2" << endl;
// forAll(f, fPtI)
// {
// meshTools::writeOBJ(Info, pts[f[fPtI]]);
// }
// Info<< "f";
// forAll(f, fPtI)
// {
// Info << " " << fPtI + 3;
// }
// Info<< nl << endl;
return false; return false;
} }
@ -913,44 +866,6 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
d += dShift; d += dShift;
// // Output face and collapse axis for visualisation
// Info<< "# Aspect ratio = " << aspectRatio << nl
// << "# determinant = " << detJ << nl
// << "# collapseAxis = " << collapseAxis << nl
// // << "# eigenvalues = " << eVals
// << endl;
// scalar scale = 2.0*mag(fC - pts[f[0]]);
// meshTools::writeOBJ(Info, fC);
// meshTools::writeOBJ(Info, fC + scale*collapseAxis);
// Info<< "f 1 2" << endl;
// forAll(f, fPtI)
// {
// meshTools::writeOBJ(Info, pts[f[fPtI]]);
// }
// Info<< "f";
// forAll(f, fPtI)
// {
// Info << " " << fPtI + 3;
// }
// Info<< nl << "# " << d << endl;
// Info<< "# " << d.first() << " " << d.last() << endl;
// forAll(d, dI)
// {
// meshTools::writeOBJ(Info, fC + (d[dI] - dShift)*collapseAxis);
// }
// Info<< endl;
// Form two lists, one for each half of the set of points // Form two lists, one for each half of the set of points
// projected along the collapse axis. // projected along the collapse axis.
@ -989,7 +904,7 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
{ {
WarningIn WarningIn
( (
"Foam::conformalVoronoiMesh::collapseFaceToEdge" "Foam::conformalVoronoiMesh::collapseFace"
"(" "("
"const face& f," "const face& f,"
"pointField& pts," "pointField& pts,"
@ -1000,20 +915,58 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
<< endl; << endl;
} }
bool validCollapse = false; faceCollapseMode mode = fcmNone;
if
(
(fA < aspectRatio*sqr(targetFaceSize*collapseSizeLimitCoeff))
&& (limitToQuadsOrTris && f.size() <= 4)
)
{
scalar guardFraction = cvMeshControls().edgeCollapseGuardFraction();
cvMeshControls().maxCollapseFaceToPointSideLengthCoeff();
if if
( (
(dNeg.last() < guardFraction*dNeg.first()) (dNeg.last() < guardFraction*dNeg.first())
&& (dPos.first() > guardFraction*dPos.last()) && (dPos.first() > guardFraction*dPos.last())
&& (fA < aspectRatio*sqr(targetFaceSize*collapseSizeLimitCoeff))
&& f.size() <= 4
) )
{ {
validCollapse = true; mode = fcmEdge;
}
else if
(
(d.last() - d.first())
< targetFaceSize
*cvMeshControls().maxCollapseFaceToPointSideLengthCoeff()
)
{
// If the face can't be collapsed to an edge, and it has a
// small enough span, collapse it to a point.
mode = fcmPoint;
}
// else (what to check? anything?)
// {
// // Alternatively, do not topologically collapse face, but push
// // all points onto a line, so that the face area is zero and
// // either:
// // + do not create it when dualising. This may damage the edge
// // addressing of the mesh;
// // + split the face into two (or more?) edges later,
// // sacrificing topological consistency with the Delaunay.
// // Note: The fcmDeferredMultiEdge collapse must be performed at
// // the polyMesh stage as this type of collapse can't be performed
// // and still maintain topological dual consistency with the
// // Delaunay structure
// mode = fcmDeferredMultiEdge;
// }
} }
if (validCollapse) if (mode == fcmEdge)
{ {
// Arbitrarily choosing the most distant point as the index to // Arbitrarily choosing the most distant point as the index to
// collapse to. // collapse to.
@ -1036,20 +989,10 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
pts[collapseToPtI] = collapseAxis*(sum(dPos)/dPos.size() - dShift) + fC; pts[collapseToPtI] = collapseAxis*(sum(dPos)/dPos.size() - dShift) + fC;
} }
else else if (mode == fcmPoint)
{
// If the face can't be collapsed to a line, and it is small
// and low aspect ratio enough, collapse it to a point.
if
(
(d.last() - d.first()) < targetFaceSize*0.35
&& fA < aspectRatio*sqr(targetFaceSize*collapseSizeLimitCoeff)
&& f.size() <= 4
)
{ {
// Arbitrarily choosing the first point as the index to // Arbitrarily choosing the first point as the index to
// collapse to. Collapse to the face center. // collapse to. Collapse to the face centre.
label collapseToPtI = facePts.first(); label collapseToPtI = facePts.first();
@ -1059,20 +1002,47 @@ bool Foam::conformalVoronoiMesh::collapseFaceToEdge
} }
pts[collapseToPtI] = fC; pts[collapseToPtI] = fC;
validCollapse = true;
} }
// Alternatively, do not topologically collapse face, but push // // Output face and collapse axis for visualisation
// all points onto a line, so that the face area is zero and
// either:
// + do not create it when dualising. This may damage the edge
// addressing of the mesh;
// + split the face into two (or more?) edges later, sacrificing
// topological consistency with the Delaunay.
}
return validCollapse; // Info<< "# Aspect ratio = " << aspectRatio << nl
// << "# determinant = " << detJ << nl
// << "# collapseAxis = " << collapseAxis << nl
// // << "# eigenvalues = " << eVals
// << endl;
// scalar scale = 2.0*mag(fC - pts[f[0]]);
// meshTools::writeOBJ(Info, fC);
// meshTools::writeOBJ(Info, fC + scale*collapseAxis);
// Info<< "f 1 2" << endl;
// forAll(f, fPtI)
// {
// meshTools::writeOBJ(Info, pts[f[fPtI]]);
// }
// Info<< "f";
// forAll(f, fPtI)
// {
// Info << " " << fPtI + 3;
// }
// Info<< nl << "# " << d << endl;
// Info<< "# " << d.first() << " " << d.last() << endl;
// forAll(d, dI)
// {
// meshTools::writeOBJ(Info, fC + (d[dI] - dShift)*collapseAxis);
// }
// Info<< endl;
return (mode != fcmNone);
} }
@ -1149,12 +1119,12 @@ Foam::label Foam::conformalVoronoiMesh::checkPolyMeshQuality
wrongFaces wrongFaces
); );
forAllConstIter(labelHashSet, wrongFaces, iter) // forAllConstIter(labelHashSet, wrongFaces, iter)
{ // {
label faceI = iter.key(); // label faceI = iter.key();
Info<< faceI << " " << pMesh.faces()[faceI] << endl; // Info<< faceI << " " << pMesh.faces()[faceI] << endl;
} // }
return wrongFaces.size(); return wrongFaces.size();

View File

@ -44,6 +44,7 @@ void Foam::conformalVoronoiMesh::conformToSurface()
} }
} }
Foam::conformalVoronoiMesh::reconformationMode Foam::conformalVoronoiMesh::reconformationMode
Foam::conformalVoronoiMesh::reconformationControl() const Foam::conformalVoronoiMesh::reconformationControl() const
{ {
@ -69,6 +70,7 @@ Foam::conformalVoronoiMesh::reconformationControl() const
return rmNone; return rmNone;
} }
void Foam::conformalVoronoiMesh::buildSurfaceConformation void Foam::conformalVoronoiMesh::buildSurfaceConformation
( (
reconformationMode reconfMode reconformationMode reconfMode

View File

@ -223,15 +223,6 @@ inline Foam::scalar Foam::conformalVoronoiMesh::maxSurfaceProtrusion
} }
inline Foam::scalar Foam::conformalVoronoiMesh::minimumEdgeLength
(
const point& pt
) const
{
return targetCellSize(pt)*cvMeshControls().minimumEdgeLengthCoeff();
}
inline Foam::label Foam::conformalVoronoiMesh::insertPoint inline Foam::label Foam::conformalVoronoiMesh::insertPoint
( (
const point& p, const point& p,

View File

@ -147,11 +147,30 @@ Foam::cvControls::cvControls
const dictionary& filteringDict(cvMeshDict_.subDict("polyMeshFiltering")); const dictionary& filteringDict(cvMeshDict_.subDict("polyMeshFiltering"));
minimumEdgeLengthCoeff_ = readScalar filterSizeCoeff_ = readScalar
( (
filteringDict.lookup("minimumEdgeLengthCoeff") filteringDict.lookup("filterSizeCoeff")
); );
mergeClosenessCoeff_ = readScalar
(
filteringDict.lookup("mergeClosenessCoeff")
);
surfaceStepFaceAngle_ = readScalar
(
filteringDict.lookup("surfaceStepFaceAngle")
);
edgeCollapseGuardFraction_ = readScalar
(
filteringDict.lookup("edgeCollapseGuardFraction")
);
maxCollapseFaceToPointSideLengthCoeff_ = readScalar
(
filteringDict.lookup("maxCollapseFaceToPointSideLengthCoeff")
);
} }

View File

@ -147,9 +147,35 @@ class cvControls
// polyMesh filtering controls // polyMesh filtering controls
//- Minimum edge length allowed in the polyMesh, anything shorter will //- Upper limit on how close two dual vertices can be before
// be filtered - fraction of the local target cell size // being merged, fraction of the local target cell size
scalar minimumEdgeLengthCoeff_; scalar mergeClosenessCoeff_;
//- The maximum allowed angle between a boundary face normal
// and the local surface normal before face will be
// aggressively collapsed
scalar surfaceStepFaceAngle_;
//- Defining how close to the midpoint (M) of the projected
// vertices line a projected vertex (X) can be before making
// an edge collapse invalid
//
// X---X-g----------------M----X-----------g----X--X
//
// Only allow a collapse if all projected vertices are
// outwith edgeCollapseGuardFraction (g) of the distance form
// the face centre to the furthest vertex in the considered
// direction
scalar edgeCollapseGuardFraction_;
//- The maximum allowed length of the longest edge of a face
// to enable a face to be collapsed to a point, fraction of
// the local target cell size
scalar maxCollapseFaceToPointSideLengthCoeff_;
//- Upper limit on the size of faces to be filtered from,
// fraction of the local target cell size
scalar filterSizeCoeff_;
// Private Member Functions // Private Member Functions
@ -238,8 +264,20 @@ public:
//- Return removalDistCoeff //- Return removalDistCoeff
inline scalar removalDistCoeff() const; inline scalar removalDistCoeff() const;
//- Return the minimumEdgeLengthCoeff //- Return the filterSizeCoeff
inline scalar minimumEdgeLengthCoeff() const; inline scalar filterSizeCoeff() const;
//- Return the mergeClosenessCoeff
inline scalar mergeClosenessCoeff() const;
//- Return the surfaceStepFaceAngle
inline scalar surfaceStepFaceAngle() const;
//- Return the edgeCollapseGuardFraction
inline scalar edgeCollapseGuardFraction() const;
//- Return the maxCollapseFaceToPointSideLengthCoeff
inline scalar maxCollapseFaceToPointSideLengthCoeff() const;
}; };

View File

@ -115,30 +115,59 @@ inline Foam::scalar Foam::cvControls::cosAlignmentAcceptanceAngle() const
return cosAlignmentAcceptanceAngle_; return cosAlignmentAcceptanceAngle_;
} }
inline Foam::scalar Foam::cvControls::insertionDistCoeff() const inline Foam::scalar Foam::cvControls::insertionDistCoeff() const
{ {
return insertionDistCoeff_; return insertionDistCoeff_;
} }
inline Foam::scalar Foam::cvControls::faceAreaRatioCoeff() const inline Foam::scalar Foam::cvControls::faceAreaRatioCoeff() const
{ {
return faceAreaRatioCoeff_; return faceAreaRatioCoeff_;
} }
inline Foam::scalar Foam::cvControls::cosInsertionAcceptanceAngle() const inline Foam::scalar Foam::cvControls::cosInsertionAcceptanceAngle() const
{ {
return cosInsertionAcceptanceAngle_; return cosInsertionAcceptanceAngle_;
} }
inline Foam::scalar Foam::cvControls::removalDistCoeff() const inline Foam::scalar Foam::cvControls::removalDistCoeff() const
{ {
return removalDistCoeff_; return removalDistCoeff_;
} }
inline Foam::scalar Foam::cvControls::minimumEdgeLengthCoeff() const
inline Foam::scalar Foam::cvControls::filterSizeCoeff() const
{ {
return minimumEdgeLengthCoeff_; return filterSizeCoeff_;
} }
inline Foam::scalar Foam::cvControls::mergeClosenessCoeff() const
{
return mergeClosenessCoeff_;
}
inline Foam::scalar Foam::cvControls::surfaceStepFaceAngle() const
{
return surfaceStepFaceAngle_;
}
inline Foam::scalar Foam::cvControls::edgeCollapseGuardFraction() const
{
return edgeCollapseGuardFraction_;
}
inline Foam::scalar
Foam::cvControls::maxCollapseFaceToPointSideLengthCoeff() const
{
return maxCollapseFaceToPointSideLengthCoeff_;
}
// ************************************************************************* // // ************************************************************************* //