From 4fa63d9bc6c6ec7c74b1c101e5454ce02a1e1de0 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Fri, 19 Jul 2019 13:33:26 +0200 Subject: [PATCH] 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. --- .../surface/isoSurface/isoSurfaceTopo.C | 164 +++++++++--------- 1 file changed, 84 insertions(+), 80 deletions(-) diff --git a/src/sampling/surface/isoSurface/isoSurfaceTopo.C b/src/sampling/surface/isoSurface/isoSurfaceTopo.C index 744d995c7b..f2fddbaa1b 100644 --- a/src/sampling/surface/isoSurface/isoSurfaceTopo.C +++ b/src/sampling/surface/isoSurface/isoSurfaceTopo.C @@ -254,126 +254,130 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs() // Pre-filter: mark all cells with illegal base points - labelHashSet problemCells(cells.size()/128); + bitSet problemCells(cells.size()); + forAll(tetBasePtIs_, facei) { if (tetBasePtIs_[facei] == -1) { - problemCells.insert(faceOwner[facei]); + problemCells.set(faceOwner[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 - // vertices (count = 2) - Map<label> pointCount; - - // Analyse problem cells for points shared by two faces only - forAll(cells, celli) { - if (problemCells.found(celli)) - { - const cell& cFaces = cells[celli]; + // Number of times a point occurs in a cell. + // Used to detect dangling vertices (count = 2) + Map<label> pointCount; + // Analyse problem cells for points shared by two faces only + for (const label celli : problemCells) + { pointCount.clear(); - forAll(cFaces, i) + for (const label facei : cells[celli]) { - const label facei = cFaces[i]; - const face& f = faces[facei]; - forAll(f, fp) + for (const label pointi : faces[facei]) { - const label pointi = f[fp]; - - Map<label>::iterator pointFnd = pointCount.find(pointi); - if (pointFnd == pointCount.end()) - { - pointCount.insert(pointi, 1); - } - else - { - ++pointFnd(); - } + ++pointCount(pointi); } } - // Check for any points with count 2 - bool haveDangling = false; forAllConstIters(pointCount, iter) { - if (iter() == 1) + if (iter.val() == 1) { - FatalErrorInFunction << "point:" << iter.key() + FatalErrorInFunction + << "point:" << 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; - break; + problemPoints.set(iter.key()); } } + } + } - if (haveDangling) - { - // Any point next to a dangling point should not be used - // as the fan base since this would cause two duplicate - // triangles. - forAll(cFaces, i) - { - const label facei = cFaces[i]; - if (tetBasePtIs_[facei] == -1) - { - const face& f = faces[facei]; - // All the possible base points cause negative tets. - // Choose the least-worst one - scalar maxQ = -GREAT; - label maxFp = -1; + // 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) + { + if + ( + problemCells[faceOwner[facei]] + || (mesh_.isInternalFace(facei) && problemCells[faceNeighbour[facei]]) + ) + { + const face& f = faces[facei]; - label prevCount = pointCount[f.last()]; - forAll(f, fp) - { - label nextCount = pointCount[f[f.fcIndex(fp)]]; - - if (prevCount > 2 && nextCount > 2) - { - const scalar q = minTetQ(facei, fp); - if (q > maxQ) - { - maxQ = q; - maxFp = fp; - } - } - prevCount = pointCount[f[fp]]; - } + // Check if either of the points adjacent to the base point is a + // problem point. If not, the existing base point can be retained. + const label fp0 = tetBasePtIs_[facei] < 0 ? 0 : tetBasePtIs_[facei]; - if (maxFp != -1) - { - // Least worst base point - tetBasePtIs_[facei] = maxFp; - } - else - { - // No point found on face that would not result - // in some duplicate triangle. Very rare. Do what? - tetBasePtIs_[facei] = 0; - } + if + ( + !problemPoints[f[f.rcIndex(fp0)]] + && !problemPoints[f[f.fcIndex(fp0)]] + ) + { + continue; + } - nAdapted++; + // 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; + label maxFp = -1; + forAll(f, fp) + { + if + ( + !problemPoints[f[f.rcIndex(fp)]] + && !problemPoints[f[f.fcIndex(fp)]] + ) + { + const scalar q = minTetQ(facei, fp); + if (q > maxQ) + { + maxQ = q; + maxFp = fp; } } } + + if (maxFp != -1) + { + // Success! Set the new base point + tetBasePtIs_[facei] = maxFp; + } + else + { + // No point was found on face that would not result in some + // duplicate triangle. Do what? Continue and hope? Spit an + // error? Silently or noisily reduce the filtering level? + + tetBasePtIs_[facei] = 0; + } + + ++nAdapted; } } + if (debug) { Pout<< "isoSurface : adapted starting point of triangulation on " -- GitLab