1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "isoSurfaceCell.H"
27 #include "dictionary.H"
29 #include "mergePoints.H"
30 #include "tetMatcher.H"
31 #include "syncTools.H"
32 #include "addToRunTimeSelectionTable.H"
33 #include "faceTriangulation.H"
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 defineTypeNameAndDebug(Foam::isoSurfaceCell, 0);
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 Foam::scalar Foam::isoSurfaceCell::isoFraction
61 //Foam::List<Foam::triFace> Foam::isoSurfaceCell::triangulate(const face& f)
64 // faceList triFaces(f.nTriangles(mesh_.points()));
65 // label triFaceI = 0;
66 // f.triangles(mesh_.points(), triFaceI, triFaces);
68 // List<triFace> tris(triFaces.size());
69 // forAll(triFaces, i)
71 // tris[i][0] = triFaces[i][0];
72 // tris[i][1] = triFaces[i][1];
73 // tris[i][2] = triFaces[i][2];
79 Foam::isoSurfaceCell::cellCutType Foam::isoSurfaceCell::calcCutType
81 const PackedBoolList& isTet,
82 const scalarField& cellValues,
83 const scalarField& pointValues,
87 const cell& cFaces = mesh_.cells()[cellI];
89 if (isTet.get(cellI) == 1)
91 forAll(cFaces, cFaceI)
93 const face& f = mesh_.faces()[cFaces[cFaceI]];
95 for (label fp = 1; fp < f.size() - 1; fp++)
97 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
99 bool aLower = (pointValues[tri[0]] < iso_);
100 bool bLower = (pointValues[tri[1]] < iso_);
101 bool cLower = (pointValues[tri[2]] < iso_);
103 if (aLower == bLower && aLower == cLower)
115 bool cellLower = (cellValues[cellI] < iso_);
117 // First check if there is any cut in cell
118 bool edgeCut = false;
120 forAll(cFaces, cFaceI)
122 const face& f = mesh_.faces()[cFaces[cFaceI]];
124 // Check pyramids cut
127 if ((pointValues[f[fp]] < iso_) != cellLower)
139 for (label fp = 1; fp < f.size() - 1; fp++)
141 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
142 //List<triFace> tris(triangulate(f));
145 // const triFace& tri = tris[i];
147 bool aLower = (pointValues[tri[0]] < iso_);
148 bool bLower = (pointValues[tri[1]] < iso_);
149 bool cLower = (pointValues[tri[2]] < iso_);
151 if (aLower == bLower && aLower == cLower)
168 // Count actual cuts (expensive since addressing needed)
169 // Note: not needed if you don't want to preserve maxima/minima
170 // centred around cellcentre. In that case just always return CUT
172 const labelList& cPoints = mesh_.cellPoints(cellI);
178 if ((pointValues[cPoints[i]] < iso_) != cellLower)
184 if (nPyrCuts == cPoints.size())
201 void Foam::isoSurfaceCell::calcCutTypes
203 const PackedBoolList& isTet,
204 const scalarField& cVals,
205 const scalarField& pVals
208 cellCutType_.setSize(mesh_.nCells());
210 forAll(mesh_.cells(), cellI)
212 cellCutType_[cellI] = calcCutType(isTet, cVals, pVals, cellI);
214 if (cellCutType_[cellI] == CUT)
222 Pout<< "isoSurfaceCell : detected " << nCutCells_
223 << " candidate cut cells." << endl;
229 // Return the two common points between two triangles
230 Foam::labelPair Foam::isoSurfaceCell::findCommonPoints
232 const labelledTri& tri0,
233 const labelledTri& tri1
236 labelPair common(-1, -1);
239 label fp1 = findIndex(tri1, tri0[fp0]);
244 fp1 = findIndex(tri1, tri0[fp0]);
249 // So tri0[fp0] is tri1[fp1]
251 // Find next common point
252 label fp0p1 = tri0.fcIndex(fp0);
253 label fp1p1 = tri1.fcIndex(fp1);
254 label fp1m1 = tri1.rcIndex(fp1);
256 if (tri0[fp0p1] == tri1[fp1p1] || tri0[fp0p1] == tri1[fp1m1])
258 common[0] = tri0[fp0];
259 common[1] = tri0[fp0p1];
266 // Caculate centre of surface.
267 Foam::point Foam::isoSurfaceCell::calcCentre(const triSurface& s)
269 vector sum = vector::zero;
273 sum += s[i].centre(s.points());
279 // Replace surface (localPoints, localTris) with single point. Returns
280 // point. Destructs arguments.
281 Foam::pointIndexHit Foam::isoSurfaceCell::collapseSurface
283 pointField& localPoints,
284 DynamicList<labelledTri, 64>& localTris
287 pointIndexHit info(false, vector::zero, localTris.size());
289 if (localTris.size() == 1)
291 const labelledTri& tri = localTris[0];
292 info.setPoint(tri.centre(localPoints));
295 else if (localTris.size() == 2)
297 // Check if the two triangles share an edge.
298 const labelledTri& tri0 = localTris[0];
299 const labelledTri& tri1 = localTris[0];
301 labelPair shared = findCommonPoints(tri0, tri1);
309 tri0.centre(localPoints)
310 + tri1.centre(localPoints)
316 else if (localTris.size())
318 // Check if single region. Rare situation.
322 geometricSurfacePatchList(0),
326 localTris.clearStorage();
329 label nZones = surf.markZones
331 boolList(surf.nEdges(), false),
337 info.setPoint(calcCentre(surf));
346 void Foam::isoSurfaceCell::calcSnappedCc
348 const PackedBoolList& isTet,
349 const scalarField& cVals,
350 const scalarField& pVals,
352 DynamicList<point>& snappedPoints,
356 const pointField& cc = mesh_.cellCentres();
357 const pointField& pts = mesh_.points();
359 snappedCc.setSize(mesh_.nCells());
363 DynamicList<point, 64> localPoints(64);
364 DynamicList<labelledTri, 64> localTris(64);
365 Map<label> pointToLocal(64);
367 forAll(mesh_.cells(), cellI)
369 if (cellCutType_[cellI] == CUT && isTet.get(cellI) == 0)
371 scalar cVal = cVals[cellI];
373 const cell& cFaces = mesh_.cells()[cellI];
377 pointToLocal.clear();
379 // Create points for all intersections close to cell centre
380 // (i.e. from pyramid edges)
382 forAll(cFaces, cFaceI)
384 const face& f = mesh_.faces()[cFaces[cFaceI]];
388 label pointI = f[fp];
390 scalar s = isoFraction(cVal, pVals[pointI]);
392 if (s >= 0.0 && s <= 0.5)
394 if (pointToLocal.insert(pointI, localPoints.size()))
396 localPoints.append((1.0-s)*cc[cellI]+s*pts[pointI]);
402 if (localPoints.size() == 1)
404 // No need for any analysis.
405 snappedCc[cellI] = snappedPoints.size();
406 snappedPoints.append(localPoints[0]);
408 //Pout<< "cell:" << cellI
409 // << " at " << mesh_.cellCentres()[cellI]
410 // << " collapsing " << localPoints
411 // << " intersections down to "
412 // << snappedPoints[snappedCc[cellI]] << endl;
414 else if (localPoints.size() == 2)
416 //? No need for any analysis.???
417 snappedCc[cellI] = snappedPoints.size();
418 snappedPoints.append(0.5*(localPoints[0]+localPoints[1]));
420 //Pout<< "cell:" << cellI
421 // << " at " << mesh_.cellCentres()[cellI]
422 // << " collapsing " << localPoints
423 // << " intersections down to "
424 // << snappedPoints[snappedCc[cellI]] << endl;
426 else if (localPoints.size())
429 forAll(cFaces, cFaceI)
431 const face& f = mesh_.faces()[cFaces[cFaceI]];
433 // Do a tetrahedrisation. Each face to cc becomes pyr.
434 // Each pyr gets split into tets by diagonalisation
437 for (label fp = 1; fp < f.size() - 1; fp++)
439 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
440 //List<triFace> tris(triangulate(f));
443 // const triFace& tri = tris[i];
445 // Get fractions for the three edges to cell centre
446 FixedList<scalar, 3> s(3);
447 s[0] = isoFraction(cVal, pVals[tri[0]]);
448 s[1] = isoFraction(cVal, pVals[tri[1]]);
449 s[2] = isoFraction(cVal, pVals[tri[2]]);
453 (s[0] >= 0.0 && s[0] <= 0.5)
454 && (s[1] >= 0.0 && s[1] <= 0.5)
455 && (s[2] >= 0.0 && s[2] <= 0.5)
462 pointToLocal[tri[0]],
463 pointToLocal[tri[1]],
464 pointToLocal[tri[2]],
472 pointField surfPoints;
473 surfPoints.transfer(localPoints);
474 pointIndexHit info = collapseSurface(surfPoints, localTris);
478 snappedCc[cellI] = snappedPoints.size();
479 snappedPoints.append(info.hitPoint());
481 //Pout<< "cell:" << cellI
482 // << " at " << mesh_.cellCentres()[cellI]
483 // << " collapsing " << surfPoints
484 // << " intersections down to "
485 // << snappedPoints[snappedCc[cellI]] << endl;
493 // Generate triangles for face connected to pointI
494 void Foam::isoSurfaceCell::genPointTris
496 const scalarField& cellValues,
497 const scalarField& pointValues,
501 DynamicList<point, 64>& localTriPoints
504 const pointField& cc = mesh_.cellCentres();
505 const pointField& pts = mesh_.points();
507 for (label fp = 1; fp < f.size() - 1; fp++)
509 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
510 //List<triFace> tris(triangulate(f));
513 // const triFace& tri = tris[i];
515 label index = findIndex(tri, pointI);
522 // Tet between index..index-1, index..index+1, index..cc
523 label b = tri[tri.fcIndex(index)];
524 label c = tri[tri.rcIndex(index)];
526 // Get fractions for the three edges emanating from point
527 FixedList<scalar, 3> s(3);
528 s[0] = isoFraction(pointValues[pointI], pointValues[b]);
529 s[1] = isoFraction(pointValues[pointI], pointValues[c]);
530 s[2] = isoFraction(pointValues[pointI], cellValues[cellI]);
534 (s[0] >= 0.0 && s[0] <= 0.5)
535 && (s[1] >= 0.0 && s[1] <= 0.5)
536 && (s[2] >= 0.0 && s[2] <= 0.5)
539 localTriPoints.append((1.0-s[0])*pts[pointI] + s[0]*pts[b]);
540 localTriPoints.append((1.0-s[1])*pts[pointI] + s[1]*pts[c]);
541 localTriPoints.append((1.0-s[2])*pts[pointI] + s[2]*cc[cellI]);
547 // Generate triangle for tet connected to pointI
548 void Foam::isoSurfaceCell::genPointTris
550 const scalarField& pointValues,
553 DynamicList<point, 64>& localTriPoints
556 const pointField& pts = mesh_.points();
557 const cell& cFaces = mesh_.cells()[cellI];
559 FixedList<label, 4> tet;
561 label face0 = cFaces[0];
562 const face& f0 = mesh_.faces()[face0];
564 if (mesh_.faceOwner()[face0] != cellI)
577 // Find the point on the next face that is not on f0
578 const face& f1 = mesh_.faces()[cFaces[1]];
584 if (p1 != tet[0] && p1 != tet[1] && p1 != tet[2])
592 // Get the index of pointI
594 label i0 = findIndex(tet, pointI);
595 label i1 = tet.fcIndex(i0);
596 label i2 = tet.fcIndex(i1);
597 label i3 = tet.fcIndex(i2);
599 // Get fractions for the three edges emanating from point
600 FixedList<scalar, 3> s(3);
601 s[0] = isoFraction(pointValues[pointI], pointValues[tet[i1]]);
602 s[1] = isoFraction(pointValues[pointI], pointValues[tet[i2]]);
603 s[2] = isoFraction(pointValues[pointI], pointValues[tet[i3]]);
607 (s[0] >= 0.0 && s[0] <= 0.5)
608 && (s[1] >= 0.0 && s[1] <= 0.5)
609 && (s[2] >= 0.0 && s[2] <= 0.5)
612 localTriPoints.append((1.0-s[0])*pts[pointI] + s[0]*pts[tet[i1]]);
613 localTriPoints.append((1.0-s[1])*pts[pointI] + s[1]*pts[tet[i2]]);
614 localTriPoints.append((1.0-s[2])*pts[pointI] + s[2]*pts[tet[i3]]);
619 void Foam::isoSurfaceCell::calcSnappedPoint
621 const PackedBoolList& isBoundaryPoint,
622 const PackedBoolList& isTet,
623 const scalarField& cVals,
624 const scalarField& pVals,
626 DynamicList<point>& snappedPoints,
627 labelList& snappedPoint
630 pointField collapsedPoint(mesh_.nPoints(), point::max);
634 DynamicList<point, 64> localTriPoints(100);
635 labelHashSet localPointCells(100);
637 forAll(mesh_.pointFaces(), pointI)
639 if (isBoundaryPoint.get(pointI) == 1)
644 const labelList& pFaces = mesh_.pointFaces()[pointI];
650 label faceI = pFaces[i];
654 cellCutType_[mesh_.faceOwner()[faceI]] == CUT
656 mesh_.isInternalFace(faceI)
657 && cellCutType_[mesh_.faceNeighbour()[faceI]] == CUT
672 localPointCells.clear();
673 localTriPoints.clear();
675 forAll(pFaces, pFaceI)
677 label faceI = pFaces[pFaceI];
678 const face& f = mesh_.faces()[faceI];
679 label own = mesh_.faceOwner()[faceI];
681 // Triangulate around f[0] on owner side
682 if (isTet.get(own) == 1)
684 if (localPointCells.insert(own))
686 genPointTris(pVals, pointI, own, localTriPoints);
691 genPointTris(cVals, pVals, pointI, f, own, localTriPoints);
694 if (mesh_.isInternalFace(faceI))
696 label nei = mesh_.faceNeighbour()[faceI];
698 if (isTet.get(nei) == 1)
700 if (localPointCells.insert(nei))
702 genPointTris(pVals, pointI, nei, localTriPoints);
707 genPointTris(cVals, pVals, pointI, f, nei, localTriPoints);
712 if (localTriPoints.size() == 3)
714 // Single triangle. No need for any analysis. Average points.
716 points.transfer(localTriPoints);
717 collapsedPoint[pointI] = sum(points)/points.size();
719 //Pout<< " point:" << pointI
720 // << " replacing coord:" << mesh_.points()[pointI]
721 // << " by average:" << collapsedPoint[pointI] << endl;
723 else if (localTriPoints.size())
725 // Convert points into triSurface.
727 // Merge points and compact out non-valid triangles
728 labelList triMap; // merged to unmerged triangle
729 labelList triPointReverseMap; // unmerged to merged point
734 false, // do not check for duplicate tris
742 label nZones = surf.markZones
744 boolList(surf.nEdges(), false),
750 collapsedPoint[pointI] = calcCentre(surf);
751 //Pout<< " point:" << pointI << " nZones:" << nZones
752 // << " replacing coord:" << mesh_.points()[pointI]
753 // << " by average:" << collapsedPoint[pointI] << endl;
758 syncTools::syncPointPositions
766 snappedPoint.setSize(mesh_.nPoints());
769 forAll(collapsedPoint, pointI)
771 if (collapsedPoint[pointI] != point::max)
773 snappedPoint[pointI] = snappedPoints.size();
774 snappedPoints.append(collapsedPoint[pointI]);
782 Foam::triSurface Foam::isoSurfaceCell::stitchTriPoints
784 const bool checkDuplicates,
785 const List<point>& triPoints,
786 labelList& triPointReverseMap, // unmerged to merged point
787 labelList& triMap // merged to unmerged triangle
790 label nTris = triPoints.size()/3;
792 if ((triPoints.size() % 3) != 0)
794 FatalErrorIn("isoSurfaceCell::stitchTriPoints(..)")
795 << "Problem: number of points " << triPoints.size()
796 << " not a multiple of 3." << abort(FatalError);
799 pointField newPoints;
809 // Check that enough merged.
812 pointField newNewPoints;
814 bool hasMerged = mergePoints
825 FatalErrorIn("isoSurfaceCell::stitchTriPoints(..)")
826 << "Merged points contain duplicates"
827 << " when merging with distance " << mergeDistance_ << endl
828 << "merged:" << newPoints.size() << " re-merged:"
829 << newNewPoints.size()
830 << abort(FatalError);
835 List<labelledTri> tris;
837 DynamicList<labelledTri> dynTris(nTris);
839 DynamicList<label> newToOldTri(nTris);
841 for (label oldTriI = 0; oldTriI < nTris; oldTriI++)
845 triPointReverseMap[rawPointI],
846 triPointReverseMap[rawPointI+1],
847 triPointReverseMap[rawPointI+2],
852 if ((tri[0] != tri[1]) && (tri[0] != tri[2]) && (tri[1] != tri[2]))
854 newToOldTri.append(oldTriI);
859 triMap.transfer(newToOldTri);
860 tris.transfer(dynTris);
864 // Use face centres to determine 'flat hole' situation (see RMT paper).
865 // Two unconnected triangles get connected because (some of) the edges
866 // separating them get collapsed. Below only checks for duplicate triangles,
867 // not non-manifold edge connectivity.
872 Pout<< "isoSurfaceCell : merged from " << nTris
873 << " down to " << tris.size() << " triangles." << endl;
876 pointField centres(tris.size());
879 centres[triI] = tris[triI].centre(newPoints);
882 pointField mergedCentres;
883 labelList oldToMerged;
884 bool hasMerged = mergePoints
895 Pout<< "isoSurfaceCell : detected "
896 << centres.size()-mergedCentres.size()
897 << " duplicate triangles." << endl;
902 // Filter out duplicates.
904 DynamicList<label> newToOldTri(tris.size());
905 labelList newToMaster(mergedCentres.size(), -1);
908 label mergedI = oldToMerged[triI];
910 if (newToMaster[mergedI] == -1)
912 newToMaster[mergedI] = triI;
913 newToOldTri.append(triMap[triI]);
914 tris[newTriI++] = tris[triI];
918 triMap.transfer(newToOldTri);
919 tris.setSize(newTriI);
923 return triSurface(tris, geometricSurfacePatchList(0), newPoints, true);
927 // Does face use valid vertices?
928 bool Foam::isoSurfaceCell::validTri(const triSurface& surf, const label faceI)
930 // Simple check on indices ok.
932 const labelledTri& f = surf[faceI];
936 if (f[fp] < 0 || f[fp] >= surf.points().size())
938 WarningIn("validTri(const triSurface&, const label)")
939 << "triangle " << faceI << " vertices " << f
940 << " uses point indices outside point range 0.."
941 << surf.points().size()-1 << endl;
947 if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
949 WarningIn("validTri(const triSurface&, const label)")
950 << "triangle " << faceI
951 << " uses non-unique vertices " << f
956 // duplicate triangle check
958 const labelList& fFaces = surf.faceFaces()[faceI];
960 // Check if faceNeighbours use same points as this face.
961 // Note: discards normal information - sides of baffle are merged.
964 label nbrFaceI = fFaces[i];
966 if (nbrFaceI <= faceI)
968 // lower numbered faces already checked
972 const labelledTri& nbrF = surf[nbrFaceI];
976 ((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
977 && ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
978 && ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
981 WarningIn("validTri(const triSurface&, const label)")
982 << "triangle " << faceI << " vertices " << f
983 << " has the same vertices as triangle " << nbrFaceI
984 << " vertices " << nbrF
994 void Foam::isoSurfaceCell::calcAddressing
996 const triSurface& surf,
997 List<FixedList<label, 3> >& faceEdges,
998 labelList& edgeFace0,
999 labelList& edgeFace1,
1000 Map<labelList>& edgeFacesRest
1003 const pointField& points = surf.points();
1005 pointField edgeCentres(3*surf.size());
1009 const labelledTri& tri = surf[triI];
1010 edgeCentres[edgeI++] = 0.5*(points[tri[0]]+points[tri[1]]);
1011 edgeCentres[edgeI++] = 0.5*(points[tri[1]]+points[tri[2]]);
1012 edgeCentres[edgeI++] = 0.5*(points[tri[2]]+points[tri[0]]);
1015 pointField mergedCentres;
1016 labelList oldToMerged;
1017 bool hasMerged = mergePoints
1028 Pout<< "isoSurfaceCell : detected "
1029 << mergedCentres.size()
1030 << " edges on " << surf.size() << " triangles." << endl;
1039 // Determine faceEdges
1040 faceEdges.setSize(surf.size());
1044 faceEdges[triI][0] = oldToMerged[edgeI++];
1045 faceEdges[triI][1] = oldToMerged[edgeI++];
1046 faceEdges[triI][2] = oldToMerged[edgeI++];
1050 // Determine edgeFaces
1051 edgeFace0.setSize(mergedCentres.size());
1053 edgeFace1.setSize(mergedCentres.size());
1055 edgeFacesRest.clear();
1057 forAll(oldToMerged, oldEdgeI)
1059 label triI = oldEdgeI / 3;
1060 label edgeI = oldToMerged[oldEdgeI];
1062 if (edgeFace0[edgeI] == -1)
1064 edgeFace0[edgeI] = triI;
1066 else if (edgeFace1[edgeI] == -1)
1068 edgeFace1[edgeI] = triI;
1072 //WarningIn("orientSurface(triSurface&)")
1073 // << "Edge " << edgeI << " with centre " << mergedCentres[edgeI]
1074 // << " used by more than two triangles: " << edgeFace0[edgeI]
1076 // << edgeFace1[edgeI] << " and " << triI << endl;
1077 Map<labelList>::iterator iter = edgeFacesRest.find(edgeI);
1079 if (iter != edgeFacesRest.end())
1081 labelList& eFaces = iter();
1082 label sz = eFaces.size();
1083 eFaces.setSize(sz+1);
1088 edgeFacesRest.insert(edgeI, labelList(1, triI));
1095 void Foam::isoSurfaceCell::walkOrientation
1097 const triSurface& surf,
1098 const List<FixedList<label, 3> >& faceEdges,
1099 const labelList& edgeFace0,
1100 const labelList& edgeFace1,
1101 const label seedTriI,
1102 labelList& flipState
1105 // Do walk for consistent orientation.
1106 DynamicList<label> changedFaces(surf.size());
1108 changedFaces.append(seedTriI);
1110 while (changedFaces.size())
1112 DynamicList<label> newChangedFaces(changedFaces.size());
1114 forAll(changedFaces, i)
1116 label triI = changedFaces[i];
1117 const labelledTri& tri = surf[triI];
1118 const FixedList<label, 3>& fEdges = faceEdges[triI];
1122 label edgeI = fEdges[fp];
1126 label p1 = tri[tri.fcIndex(fp)];
1130 edgeFace0[edgeI] != triI
1135 if (nbrI != -1 && flipState[nbrI] == -1)
1137 const labelledTri& nbrTri = surf[nbrI];
1140 label nbrFp = findIndex(nbrTri, p0);
1141 label nbrP1 = nbrTri[nbrTri.rcIndex(nbrFp)];
1143 bool sameOrientation = (p1 == nbrP1);
1145 if (flipState[triI] == 0)
1147 flipState[nbrI] = (sameOrientation ? 0 : 1);
1151 flipState[nbrI] = (sameOrientation ? 1 : 0);
1153 newChangedFaces.append(nbrI);
1158 changedFaces.transfer(newChangedFaces);
1163 void Foam::isoSurfaceCell::orientSurface
1166 const List<FixedList<label, 3> >& faceEdges,
1167 const labelList& edgeFace0,
1168 const labelList& edgeFace1,
1169 const Map<labelList>& edgeFacesRest
1175 labelList flipState(surf.size(), -1);
1181 // Find first unvisited triangle
1185 seedTriI < surf.size() && flipState[seedTriI] != -1;
1190 if (seedTriI == surf.size())
1195 // Note: Determine orientation of seedTriI?
1196 // for now assume it is ok
1197 flipState[seedTriI] = 0;
1210 // Do actual flipping
1214 if (flipState[triI] == 1)
1216 labelledTri tri(surf[triI]);
1218 surf[triI][0] = tri[0];
1219 surf[triI][1] = tri[2];
1220 surf[triI][2] = tri[1];
1222 else if (flipState[triI] == -1)
1226 "isoSurfaceCell::orientSurface(triSurface&, const label)"
1227 ) << "problem" << abort(FatalError);
1233 // Checks if triangle is connected through edgeI only.
1234 bool Foam::isoSurfaceCell::danglingTriangle
1236 const FixedList<label, 3>& fEdges,
1237 const labelList& edgeFace1
1243 if (edgeFace1[fEdges[i]] == -1)
1249 if (nOpen == 1 || nOpen == 2 || nOpen == 3)
1260 // Mark triangles to keep. Returns number of dangling triangles.
1261 Foam::label Foam::isoSurfaceCell::markDanglingTriangles
1263 const List<FixedList<label, 3> >& faceEdges,
1264 const labelList& edgeFace0,
1265 const labelList& edgeFace1,
1266 const Map<labelList>& edgeFacesRest,
1267 boolList& keepTriangles
1270 keepTriangles.setSize(faceEdges.size());
1271 keepTriangles = true;
1273 label nDangling = 0;
1275 // Remove any dangling triangles
1276 forAllConstIter(Map<labelList>, edgeFacesRest, iter)
1278 // These are all the non-manifold edges. Filter out all triangles
1279 // with only one connected edge (= this edge)
1281 label edgeI = iter.key();
1282 const labelList& otherEdgeFaces = iter();
1284 // Remove all dangling triangles
1285 if (danglingTriangle(faceEdges[edgeFace0[edgeI]], edgeFace1))
1287 keepTriangles[edgeFace0[edgeI]] = false;
1290 if (danglingTriangle(faceEdges[edgeFace1[edgeI]], edgeFace1))
1292 keepTriangles[edgeFace1[edgeI]] = false;
1295 forAll(otherEdgeFaces, i)
1297 label triI = otherEdgeFaces[i];
1298 if (danglingTriangle(faceEdges[triI], edgeFace1))
1300 keepTriangles[triI] = false;
1309 Foam::triSurface Foam::isoSurfaceCell::subsetMesh
1311 const triSurface& s,
1312 const labelList& newToOldFaces,
1313 labelList& oldToNewPoints,
1314 labelList& newToOldPoints
1317 const boolList include
1319 createWithValues<boolList>
1328 newToOldPoints.setSize(s.points().size());
1329 oldToNewPoints.setSize(s.points().size());
1330 oldToNewPoints = -1;
1334 forAll(include, oldFacei)
1336 if (include[oldFacei])
1338 // Renumber labels for face
1339 const triSurface::FaceType& f = s[oldFacei];
1343 label oldPointI = f[fp];
1345 if (oldToNewPoints[oldPointI] == -1)
1347 oldToNewPoints[oldPointI] = pointI;
1348 newToOldPoints[pointI++] = oldPointI;
1353 newToOldPoints.setSize(pointI);
1357 pointField newPoints(newToOldPoints.size());
1358 forAll(newToOldPoints, i)
1360 newPoints[i] = s.points()[newToOldPoints[i]];
1363 List<labelledTri> newTriangles(newToOldFaces.size());
1365 forAll(newToOldFaces, i)
1367 // Get old vertex labels
1368 const labelledTri& tri = s[newToOldFaces[i]];
1370 newTriangles[i][0] = oldToNewPoints[tri[0]];
1371 newTriangles[i][1] = oldToNewPoints[tri[1]];
1372 newTriangles[i][2] = oldToNewPoints[tri[2]];
1373 newTriangles[i].region() = tri.region();
1377 return triSurface(newTriangles, s.patches(), newPoints, true);
1381 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1383 Foam::isoSurfaceCell::isoSurfaceCell
1385 const polyMesh& mesh,
1386 const scalarField& cVals,
1387 const scalarField& pVals,
1389 const bool regularise,
1390 const scalar mergeTol
1397 mergeDistance_(mergeTol*mesh.bounds().mag())
1399 // Determine if cell is tet
1400 PackedBoolList isTet(mesh_.nCells());
1404 forAll(isTet, cellI)
1406 if (tet.isA(mesh_, cellI))
1408 isTet.set(cellI, 1);
1413 // Determine if point is on boundary. Points on boundaries are never
1414 // snapped. Coupled boundaries are handled explicitly so not marked here.
1415 PackedBoolList isBoundaryPoint(mesh_.nPoints());
1416 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1417 forAll(patches, patchI)
1419 const polyPatch& pp = patches[patchI];
1423 label faceI = pp.start();
1426 const face& f = mesh_.faces()[faceI++];
1430 isBoundaryPoint.set(f[fp], 1);
1437 // Determine if any cut through cell
1438 calcCutTypes(isTet, cVals, pVals);
1440 DynamicList<point> snappedPoints(nCutCells_);
1442 // Per cc -1 or a point inside snappedPoints.
1443 labelList snappedCc;
1457 snappedCc.setSize(mesh_.nCells());
1463 Pout<< "isoSurfaceCell : shifted " << snappedPoints.size()
1464 << " cell centres to intersection." << endl;
1467 snappedPoints.shrink();
1468 label nCellSnaps = snappedPoints.size();
1470 // Per point -1 or a point inside snappedPoints.
1471 labelList snappedPoint;
1486 snappedPoint.setSize(mesh_.nPoints());
1492 Pout<< "isoSurfaceCell : shifted " << snappedPoints.size()-nCellSnaps
1493 << " vertices to intersection." << endl;
1498 DynamicList<point> triPoints(nCutCells_);
1499 DynamicList<label> triMeshCells(nCutCells_);
1506 mesh_.cellCentres(),
1519 Pout<< "isoSurfaceCell : generated " << triMeshCells.size()
1520 << " unmerged triangles." << endl;
1523 // Merge points and compact out non-valid triangles
1524 labelList triMap; // merged to unmerged triangle
1525 triSurface::operator=
1529 true, // check for duplicate tris
1531 triPointMergeMap_, // unmerged to merged point
1538 Pout<< "isoSurfaceCell : generated " << triMap.size()
1539 << " merged triangles." << endl;
1542 meshCells_.setSize(triMap.size());
1545 meshCells_[i] = triMeshCells[triMap[i]];
1550 Pout<< "isoSurfaceCell : checking " << size()
1551 << " triangles for validity." << endl;
1555 // Copied from surfaceCheck
1556 validTri(*this, triI);
1563 List<FixedList<label, 3> > faceEdges;
1564 labelList edgeFace0, edgeFace1;
1565 Map<labelList> edgeFacesRest;
1570 // Calculate addressing
1580 // See if any dangling triangles
1581 boolList keepTriangles;
1582 label nDangling = markDanglingTriangles
1593 Pout<< "isoSurfaceCell : detected " << nDangling
1594 << " dangling triangles." << endl;
1602 // Create face map (new to old)
1603 labelList subsetTriMap(findIndices(keepTriangles, true));
1605 labelList subsetPointMap;
1606 labelList reversePointMap;
1607 triSurface::operator=
1617 meshCells_ = labelField(meshCells_, subsetTriMap);
1618 inplaceRenumber(reversePointMap, triPointMergeMap_);
1621 orientSurface(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
1623 //combineCellTriangles();
1628 //// Experimental retriangulation of triangles per cell. Problem is that
1629 //// -it is very expensive -only gets rid of internal points, not of boundary
1630 //// ones so limited benefit (e.g. 60 v.s. 88 triangles)
1631 //void Foam::isoSurfaceCell::combineCellTriangles()
1635 // DynamicList<labelledTri> newTris(size());
1636 // DynamicList<label> newTriToCell(size());
1638 // label startTriI = 0;
1640 // DynamicList<labelledTri> tris;
1642 // for (label triI = 1; triI <= meshCells_.size(); triI++)
1646 // triI == meshCells_.size()
1647 // || meshCells_[triI] != meshCells_[startTriI]
1650 // label nTris = triI-startTriI;
1654 // newTris.append(operator[](startTriI));
1655 // newTriToCell.append(meshCells_[startTriI]);
1659 // // Collect from startTriI to triI in a triSurface
1661 // for (label i = startTriI; i < triI; i++)
1663 // tris.append(operator[](i));
1665 // triSurface cellTris(tris, patches(), points());
1669 // const labelListList& loops = cellTris.edgeLoops();
1673 // // Do proper triangulation of loop
1674 // face loop(renumber(cellTris.meshPoints(), loops[i]));
1676 // faceTriangulation faceTris
1683 // // Copy into newTris
1684 // forAll(faceTris, faceTriI)
1686 // const triFace& tri = faceTris[faceTriI];
1695 // operator[](startTriI).region()
1698 // newTriToCell.append(meshCells_[startTriI]);
1703 // startTriI = triI;
1706 // newTris.shrink();
1707 // newTriToCell.shrink();
1710 // pointField newPoints(points().size());
1711 // label newPointI = 0;
1712 // labelList oldToNewPoint(points().size(), -1);
1714 // forAll(newTris, i)
1716 // labelledTri& tri = newTris[i];
1719 // label pointI = tri[j];
1721 // if (oldToNewPoint[pointI] == -1)
1723 // oldToNewPoint[pointI] = newPointI;
1724 // newPoints[newPointI++] = points()[pointI];
1726 // tri[j] = oldToNewPoint[pointI];
1729 // newPoints.setSize(newPointI);
1731 // triSurface::operator=
1741 // meshCells_.transfer(newTriToCell);
1746 // ************************************************************************* //