ENH: improvements for isoSurfaceTopo erosion (#1374)

- adapted openfoam.org code.  Original commit message:

  Instead of adapting tet base points cell-by-cell, the dangling
  points are pre-computed and then the adaptations to the base points
  are made face-by-face. This correctly adapts faces which have
  different dangling points relative to the owner and neighbour cells.
This commit is contained in:
Mark Olesen
2019-07-19 13:33:26 +02:00
committed by Andrew Heather
parent 2689202a3d
commit 9e7ad6e511

View File

@ -254,96 +254,101 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs()
// Pre-filter: mark all cells with illegal base points // Pre-filter: mark all cells with illegal base points
labelHashSet problemCells(cells.size()/128); bitSet problemCells(cells.size());
forAll(tetBasePtIs_, facei) forAll(tetBasePtIs_, facei)
{ {
if (tetBasePtIs_[facei] == -1) if (tetBasePtIs_[facei] == -1)
{ {
problemCells.insert(faceOwner[facei]); problemCells.set(faceOwner[facei]);
if (mesh_.isInternalFace(facei)) if (mesh_.isInternalFace(facei))
{ {
problemCells.insert(faceNeighbour[facei]); problemCells.set(faceNeighbour[facei]);
} }
} }
} }
label nAdapted = 0; // Mark all points that are shared by just two faces within an adjacent
// problem cell as problematic
bitSet problemPoints(mesh_.points().size());
{
// Number of times a point occurs in a cell. Used to detect dangling // Number of times a point occurs in a cell.
// vertices (count = 2) // Used to detect dangling vertices (count = 2)
Map<label> pointCount; Map<label> pointCount;
// Analyse problem cells for points shared by two faces only // Analyse problem cells for points shared by two faces only
forAll(cells, celli) for (const label celli : problemCells)
{ {
if (problemCells.found(celli))
{
const cell& cFaces = cells[celli];
pointCount.clear(); pointCount.clear();
forAll(cFaces, i) for (const label facei : cells[celli])
{ {
const label facei = cFaces[i]; for (const label pointi : faces[facei])
const face& f = faces[facei];
forAll(f, fp)
{ {
const label pointi = f[fp]; ++pointCount(pointi);
Map<label>::iterator pointFnd = pointCount.find(pointi);
if (pointFnd == pointCount.end())
{
pointCount.insert(pointi, 1);
}
else
{
++pointFnd();
}
} }
} }
// Check for any points with count 2
bool haveDangling = false;
forAllConstIters(pointCount, iter) forAllConstIters(pointCount, iter)
{ {
if (iter() == 1) if (iter.val() == 1)
{ {
FatalErrorInFunction << "point:" << iter.key() FatalErrorInFunction
<< "point:" << iter.key()
<< " at:" << mesh_.points()[iter.key()] << " at:" << mesh_.points()[iter.key()]
<< " only used by one face" << exit(FatalError); << " only used by one face" << nl
<< exit(FatalError);
} }
else if (iter() == 2) else if (iter.val() == 2)
{ {
haveDangling = true; problemPoints.set(iter.key());
break; }
}
} }
} }
if (haveDangling)
// For all faces which form a part of a problem-cell, check if the base
// point is adjacent to any problem points. If it is, re-calculate the base
// point so that it is not.
label nAdapted = 0;
forAll(tetBasePtIs_, facei)
{ {
// Any point next to a dangling point should not be used if
// as the fan base since this would cause two duplicate (
// triangles. problemCells[faceOwner[facei]]
forAll(cFaces, i) || (mesh_.isInternalFace(facei) && problemCells[faceNeighbour[facei]])
{ )
const label facei = cFaces[i];
if (tetBasePtIs_[facei] == -1)
{ {
const face& f = faces[facei]; const face& f = faces[facei];
// All the possible base points cause negative tets. // Check if either of the points adjacent to the base point is a
// Choose the least-worst one // problem point. If not, the existing base point can be retained.
const label fp0 = tetBasePtIs_[facei] < 0 ? 0 : tetBasePtIs_[facei];
if
(
!problemPoints[f[f.rcIndex(fp0)]]
&& !problemPoints[f[f.fcIndex(fp0)]]
)
{
continue;
}
// A new base point is required. Pick the point that results in the
// least-worst tet and which is not adjacent to any problem points.
scalar maxQ = -GREAT; scalar maxQ = -GREAT;
label maxFp = -1; label maxFp = -1;
label prevCount = pointCount[f.last()];
forAll(f, fp) forAll(f, fp)
{ {
label nextCount = pointCount[f[f.fcIndex(fp)]]; if
(
if (prevCount > 2 && nextCount > 2) !problemPoints[f[f.rcIndex(fp)]]
&& !problemPoints[f[f.fcIndex(fp)]]
)
{ {
const scalar q = minTetQ(facei, fp); const scalar q = minTetQ(facei, fp);
if (q > maxQ) if (q > maxQ)
@ -352,28 +357,27 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs()
maxFp = fp; maxFp = fp;
} }
} }
prevCount = pointCount[f[fp]];
} }
if (maxFp != -1) if (maxFp != -1)
{ {
// Least worst base point // Success! Set the new base point
tetBasePtIs_[facei] = maxFp; tetBasePtIs_[facei] = maxFp;
} }
else else
{ {
// No point found on face that would not result // No point was found on face that would not result in some
// in some duplicate triangle. Very rare. Do what? // duplicate triangle. Do what? Continue and hope? Spit an
// error? Silently or noisily reduce the filtering level?
tetBasePtIs_[facei] = 0; tetBasePtIs_[facei] = 0;
} }
nAdapted++; ++nAdapted;
}
}
}
} }
} }
if (debug) if (debug)
{ {
Pout<< "isoSurface : adapted starting point of triangulation on " Pout<< "isoSurface : adapted starting point of triangulation on "