1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
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 * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(isoSurfaceCell, 0);
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 Foam::scalar Foam::isoSurfaceCell::isoFraction
63 //Foam::List<Foam::triFace> Foam::isoSurfaceCell::triangulate(const face& f)
66 // faceList triFaces(f.nTriangles(mesh_.points()));
67 // label triFaceI = 0;
68 // f.triangles(mesh_.points(), triFaceI, triFaces);
70 // List<triFace> tris(triFaces.size());
71 // forAll(triFaces, i)
73 // tris[i][0] = triFaces[i][0];
74 // tris[i][1] = triFaces[i][1];
75 // tris[i][2] = triFaces[i][2];
81 Foam::isoSurfaceCell::cellCutType Foam::isoSurfaceCell::calcCutType
83 const PackedBoolList& isTet,
84 const scalarField& cellValues,
85 const scalarField& pointValues,
89 const cell& cFaces = mesh_.cells()[cellI];
91 if (isTet.get(cellI) == 1)
93 forAll(cFaces, cFaceI)
95 const face& f = mesh_.faces()[cFaces[cFaceI]];
97 for (label fp = 1; fp < f.size() - 1; fp++)
99 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
101 bool aLower = (pointValues[tri[0]] < iso_);
102 bool bLower = (pointValues[tri[1]] < iso_);
103 bool cLower = (pointValues[tri[2]] < iso_);
105 if (aLower == bLower && aLower == cLower)
117 bool cellLower = (cellValues[cellI] < iso_);
119 // First check if there is any cut in cell
120 bool edgeCut = false;
122 forAll(cFaces, cFaceI)
124 const face& f = mesh_.faces()[cFaces[cFaceI]];
126 // Check pyramids cut
129 if ((pointValues[f[fp]] < iso_) != cellLower)
141 for (label fp = 1; fp < f.size() - 1; fp++)
143 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
144 //List<triFace> tris(triangulate(f));
147 // const triFace& tri = tris[i];
149 bool aLower = (pointValues[tri[0]] < iso_);
150 bool bLower = (pointValues[tri[1]] < iso_);
151 bool cLower = (pointValues[tri[2]] < iso_);
153 if (aLower == bLower && aLower == cLower)
170 // Count actual cuts (expensive since addressing needed)
171 // Note: not needed if you don't want to preserve maxima/minima
172 // centred around cellcentre. In that case just always return CUT
174 const labelList& cPoints = mesh_.cellPoints(cellI);
180 if ((pointValues[cPoints[i]] < iso_) != cellLower)
186 if (nPyrCuts == cPoints.size())
203 void Foam::isoSurfaceCell::calcCutTypes
205 const PackedBoolList& isTet,
206 const scalarField& cVals,
207 const scalarField& pVals
210 cellCutType_.setSize(mesh_.nCells());
212 forAll(mesh_.cells(), cellI)
214 cellCutType_[cellI] = calcCutType(isTet, cVals, pVals, cellI);
216 if (cellCutType_[cellI] == CUT)
224 Pout<< "isoSurfaceCell : detected " << nCutCells_
225 << " candidate cut cells." << endl;
231 // Return the two common points between two triangles
232 Foam::labelPair Foam::isoSurfaceCell::findCommonPoints
234 const labelledTri& tri0,
235 const labelledTri& tri1
238 labelPair common(-1, -1);
241 label fp1 = findIndex(tri1, tri0[fp0]);
246 fp1 = findIndex(tri1, tri0[fp0]);
251 // So tri0[fp0] is tri1[fp1]
253 // Find next common point
254 label fp0p1 = tri0.fcIndex(fp0);
255 label fp1p1 = tri1.fcIndex(fp1);
256 label fp1m1 = tri1.rcIndex(fp1);
258 if (tri0[fp0p1] == tri1[fp1p1] || tri0[fp0p1] == tri1[fp1m1])
260 common[0] = tri0[fp0];
261 common[1] = tri0[fp0p1];
268 // Caculate centre of surface.
269 Foam::point Foam::isoSurfaceCell::calcCentre(const triSurface& s)
271 vector sum = vector::zero;
275 sum += s[i].centre(s.points());
281 // Replace surface (localPoints, localTris) with single point. Returns
282 // point. Destructs arguments.
283 Foam::pointIndexHit Foam::isoSurfaceCell::collapseSurface
285 pointField& localPoints,
286 DynamicList<labelledTri, 64>& localTris
289 pointIndexHit info(false, vector::zero, localTris.size());
291 if (localTris.size() == 1)
293 const labelledTri& tri = localTris[0];
294 info.setPoint(tri.centre(localPoints));
297 else if (localTris.size() == 2)
299 // Check if the two triangles share an edge.
300 const labelledTri& tri0 = localTris[0];
301 const labelledTri& tri1 = localTris[0];
303 labelPair shared = findCommonPoints(tri0, tri1);
311 tri0.centre(localPoints)
312 + tri1.centre(localPoints)
318 else if (localTris.size())
320 // Check if single region. Rare situation.
324 geometricSurfacePatchList(0),
328 localTris.clearStorage();
331 label nZones = surf.markZones
333 boolList(surf.nEdges(), false),
339 info.setPoint(calcCentre(surf));
348 void Foam::isoSurfaceCell::calcSnappedCc
350 const PackedBoolList& isTet,
351 const scalarField& cVals,
352 const scalarField& pVals,
354 DynamicList<point>& snappedPoints,
358 const pointField& cc = mesh_.cellCentres();
359 const pointField& pts = mesh_.points();
361 snappedCc.setSize(mesh_.nCells());
365 DynamicList<point, 64> localPoints(64);
366 DynamicList<labelledTri, 64> localTris(64);
367 Map<label> pointToLocal(64);
369 forAll(mesh_.cells(), cellI)
371 if (cellCutType_[cellI] == CUT && isTet.get(cellI) == 0)
373 scalar cVal = cVals[cellI];
375 const cell& cFaces = mesh_.cells()[cellI];
379 pointToLocal.clear();
381 // Create points for all intersections close to cell centre
382 // (i.e. from pyramid edges)
384 forAll(cFaces, cFaceI)
386 const face& f = mesh_.faces()[cFaces[cFaceI]];
390 label pointI = f[fp];
392 scalar s = isoFraction(cVal, pVals[pointI]);
394 if (s >= 0.0 && s <= 0.5)
396 if (pointToLocal.insert(pointI, localPoints.size()))
398 localPoints.append((1.0-s)*cc[cellI]+s*pts[pointI]);
404 if (localPoints.size() == 1)
406 // No need for any analysis.
407 snappedCc[cellI] = snappedPoints.size();
408 snappedPoints.append(localPoints[0]);
410 //Pout<< "cell:" << cellI
411 // << " at " << mesh_.cellCentres()[cellI]
412 // << " collapsing " << localPoints
413 // << " intersections down to "
414 // << snappedPoints[snappedCc[cellI]] << endl;
416 else if (localPoints.size() == 2)
418 //? No need for any analysis.???
419 snappedCc[cellI] = snappedPoints.size();
420 snappedPoints.append(0.5*(localPoints[0]+localPoints[1]));
422 //Pout<< "cell:" << cellI
423 // << " at " << mesh_.cellCentres()[cellI]
424 // << " collapsing " << localPoints
425 // << " intersections down to "
426 // << snappedPoints[snappedCc[cellI]] << endl;
428 else if (localPoints.size())
431 forAll(cFaces, cFaceI)
433 const face& f = mesh_.faces()[cFaces[cFaceI]];
435 // Do a tetrahedrisation. Each face to cc becomes pyr.
436 // Each pyr gets split into tets by diagonalisation
439 for (label fp = 1; fp < f.size() - 1; fp++)
441 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
442 //List<triFace> tris(triangulate(f));
445 // const triFace& tri = tris[i];
447 // Get fractions for the three edges to cell centre
448 FixedList<scalar, 3> s(3);
449 s[0] = isoFraction(cVal, pVals[tri[0]]);
450 s[1] = isoFraction(cVal, pVals[tri[1]]);
451 s[2] = isoFraction(cVal, pVals[tri[2]]);
455 (s[0] >= 0.0 && s[0] <= 0.5)
456 && (s[1] >= 0.0 && s[1] <= 0.5)
457 && (s[2] >= 0.0 && s[2] <= 0.5)
464 pointToLocal[tri[0]],
465 pointToLocal[tri[1]],
466 pointToLocal[tri[2]],
474 pointField surfPoints;
475 surfPoints.transfer(localPoints);
476 pointIndexHit info = collapseSurface(surfPoints, localTris);
480 snappedCc[cellI] = snappedPoints.size();
481 snappedPoints.append(info.hitPoint());
483 //Pout<< "cell:" << cellI
484 // << " at " << mesh_.cellCentres()[cellI]
485 // << " collapsing " << surfPoints
486 // << " intersections down to "
487 // << snappedPoints[snappedCc[cellI]] << endl;
495 // Generate triangles for face connected to pointI
496 void Foam::isoSurfaceCell::genPointTris
498 const scalarField& cellValues,
499 const scalarField& pointValues,
503 DynamicList<point, 64>& localTriPoints
506 const pointField& cc = mesh_.cellCentres();
507 const pointField& pts = mesh_.points();
509 for (label fp = 1; fp < f.size() - 1; fp++)
511 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
512 //List<triFace> tris(triangulate(f));
515 // const triFace& tri = tris[i];
517 label index = findIndex(tri, pointI);
524 // Tet between index..index-1, index..index+1, index..cc
525 label b = tri[tri.fcIndex(index)];
526 label c = tri[tri.rcIndex(index)];
528 // Get fractions for the three edges emanating from point
529 FixedList<scalar, 3> s(3);
530 s[0] = isoFraction(pointValues[pointI], pointValues[b]);
531 s[1] = isoFraction(pointValues[pointI], pointValues[c]);
532 s[2] = isoFraction(pointValues[pointI], cellValues[cellI]);
536 (s[0] >= 0.0 && s[0] <= 0.5)
537 && (s[1] >= 0.0 && s[1] <= 0.5)
538 && (s[2] >= 0.0 && s[2] <= 0.5)
541 localTriPoints.append((1.0-s[0])*pts[pointI] + s[0]*pts[b]);
542 localTriPoints.append((1.0-s[1])*pts[pointI] + s[1]*pts[c]);
543 localTriPoints.append((1.0-s[2])*pts[pointI] + s[2]*cc[cellI]);
549 // Generate triangle for tet connected to pointI
550 void Foam::isoSurfaceCell::genPointTris
552 const scalarField& pointValues,
555 DynamicList<point, 64>& localTriPoints
558 const pointField& pts = mesh_.points();
559 const cell& cFaces = mesh_.cells()[cellI];
561 FixedList<label, 4> tet;
563 label face0 = cFaces[0];
564 const face& f0 = mesh_.faces()[face0];
566 if (mesh_.faceOwner()[face0] != cellI)
579 // Find the point on the next face that is not on f0
580 const face& f1 = mesh_.faces()[cFaces[1]];
586 if (p1 != tet[0] && p1 != tet[1] && p1 != tet[2])
594 // Get the index of pointI
596 label i0 = findIndex(tet, pointI);
597 label i1 = tet.fcIndex(i0);
598 label i2 = tet.fcIndex(i1);
599 label i3 = tet.fcIndex(i2);
601 // Get fractions for the three edges emanating from point
602 FixedList<scalar, 3> s(3);
603 s[0] = isoFraction(pointValues[pointI], pointValues[tet[i1]]);
604 s[1] = isoFraction(pointValues[pointI], pointValues[tet[i2]]);
605 s[2] = isoFraction(pointValues[pointI], pointValues[tet[i3]]);
609 (s[0] >= 0.0 && s[0] <= 0.5)
610 && (s[1] >= 0.0 && s[1] <= 0.5)
611 && (s[2] >= 0.0 && s[2] <= 0.5)
614 localTriPoints.append((1.0-s[0])*pts[pointI] + s[0]*pts[tet[i1]]);
615 localTriPoints.append((1.0-s[1])*pts[pointI] + s[1]*pts[tet[i2]]);
616 localTriPoints.append((1.0-s[2])*pts[pointI] + s[2]*pts[tet[i3]]);
621 void Foam::isoSurfaceCell::calcSnappedPoint
623 const PackedBoolList& isBoundaryPoint,
624 const PackedBoolList& isTet,
625 const scalarField& cVals,
626 const scalarField& pVals,
628 DynamicList<point>& snappedPoints,
629 labelList& snappedPoint
632 const point greatPoint(VGREAT, VGREAT, VGREAT);
633 pointField collapsedPoint(mesh_.nPoints(), greatPoint);
637 DynamicList<point, 64> localTriPoints(100);
638 labelHashSet localPointCells(100);
640 forAll(mesh_.pointFaces(), pointI)
642 if (isBoundaryPoint.get(pointI) == 1)
647 const labelList& pFaces = mesh_.pointFaces()[pointI];
653 label faceI = pFaces[i];
657 cellCutType_[mesh_.faceOwner()[faceI]] == CUT
659 mesh_.isInternalFace(faceI)
660 && cellCutType_[mesh_.faceNeighbour()[faceI]] == CUT
675 localPointCells.clear();
676 localTriPoints.clear();
678 forAll(pFaces, pFaceI)
680 label faceI = pFaces[pFaceI];
681 const face& f = mesh_.faces()[faceI];
682 label own = mesh_.faceOwner()[faceI];
684 // Triangulate around f[0] on owner side
685 if (isTet.get(own) == 1)
687 if (localPointCells.insert(own))
689 genPointTris(pVals, pointI, own, localTriPoints);
694 genPointTris(cVals, pVals, pointI, f, own, localTriPoints);
697 if (mesh_.isInternalFace(faceI))
699 label nei = mesh_.faceNeighbour()[faceI];
701 if (isTet.get(nei) == 1)
703 if (localPointCells.insert(nei))
705 genPointTris(pVals, pointI, nei, localTriPoints);
710 genPointTris(cVals, pVals, pointI, f, nei, localTriPoints);
715 if (localTriPoints.size() == 3)
717 // Single triangle. No need for any analysis. Average points.
719 points.transfer(localTriPoints);
720 collapsedPoint[pointI] = sum(points)/points.size();
722 //Pout<< " point:" << pointI
723 // << " replacing coord:" << mesh_.points()[pointI]
724 // << " by average:" << collapsedPoint[pointI] << endl;
726 else if (localTriPoints.size())
728 // Convert points into triSurface.
730 // Merge points and compact out non-valid triangles
731 labelList triMap; // merged to unmerged triangle
732 labelList triPointReverseMap; // unmerged to merged point
737 false, // do not check for duplicate tris
745 label nZones = surf.markZones
747 boolList(surf.nEdges(), false),
753 collapsedPoint[pointI] = calcCentre(surf);
754 //Pout<< " point:" << pointI << " nZones:" << nZones
755 // << " replacing coord:" << mesh_.points()[pointI]
756 // << " by average:" << collapsedPoint[pointI] << endl;
761 syncTools::syncPointList
767 true // are coordinates so separate
770 snappedPoint.setSize(mesh_.nPoints());
773 forAll(collapsedPoint, pointI)
775 if (collapsedPoint[pointI] != greatPoint)
777 snappedPoint[pointI] = snappedPoints.size();
778 snappedPoints.append(collapsedPoint[pointI]);
786 Foam::triSurface Foam::isoSurfaceCell::stitchTriPoints
788 const bool checkDuplicates,
789 const List<point>& triPoints,
790 labelList& triPointReverseMap, // unmerged to merged point
791 labelList& triMap // merged to unmerged triangle
794 label nTris = triPoints.size()/3;
796 if ((triPoints.size() % 3) != 0)
798 FatalErrorIn("isoSurfaceCell::stitchTriPoints(..)")
799 << "Problem: number of points " << triPoints.size()
800 << " not a multiple of 3." << abort(FatalError);
803 pointField newPoints;
813 // Check that enough merged.
816 pointField newNewPoints;
818 bool hasMerged = mergePoints
829 FatalErrorIn("isoSurfaceCell::stitchTriPoints(..)")
830 << "Merged points contain duplicates"
831 << " when merging with distance " << mergeDistance_ << endl
832 << "merged:" << newPoints.size() << " re-merged:"
833 << newNewPoints.size()
834 << abort(FatalError);
839 List<labelledTri> tris;
841 DynamicList<labelledTri> dynTris(nTris);
843 DynamicList<label> newToOldTri(nTris);
845 for (label oldTriI = 0; oldTriI < nTris; oldTriI++)
849 triPointReverseMap[rawPointI],
850 triPointReverseMap[rawPointI+1],
851 triPointReverseMap[rawPointI+2],
856 if ((tri[0] != tri[1]) && (tri[0] != tri[2]) && (tri[1] != tri[2]))
858 newToOldTri.append(oldTriI);
863 triMap.transfer(newToOldTri);
864 tris.transfer(dynTris);
868 // Use face centres to determine 'flat hole' situation (see RMT paper).
869 // Two unconnected triangles get connected because (some of) the edges
870 // separating them get collapsed. Below only checks for duplicate triangles,
871 // not non-manifold edge connectivity.
876 Pout<< "isoSurfaceCell : merged from " << nTris
877 << " down to " << tris.size() << " triangles." << endl;
880 pointField centres(tris.size());
883 centres[triI] = tris[triI].centre(newPoints);
886 pointField mergedCentres;
887 labelList oldToMerged;
888 bool hasMerged = mergePoints
899 Pout<< "isoSurfaceCell : detected "
900 << centres.size()-mergedCentres.size()
901 << " duplicate triangles." << endl;
906 // Filter out duplicates.
908 DynamicList<label> newToOldTri(tris.size());
909 labelList newToMaster(mergedCentres.size(), -1);
912 label mergedI = oldToMerged[triI];
914 if (newToMaster[mergedI] == -1)
916 newToMaster[mergedI] = triI;
917 newToOldTri.append(triMap[triI]);
918 tris[newTriI++] = tris[triI];
922 triMap.transfer(newToOldTri);
923 tris.setSize(newTriI);
927 return triSurface(tris, geometricSurfacePatchList(0), newPoints, true);
931 // Does face use valid vertices?
932 bool Foam::isoSurfaceCell::validTri(const triSurface& surf, const label faceI)
934 // Simple check on indices ok.
936 const labelledTri& f = surf[faceI];
940 (f[0] < 0) || (f[0] >= surf.points().size())
941 || (f[1] < 0) || (f[1] >= surf.points().size())
942 || (f[2] < 0) || (f[2] >= surf.points().size())
945 WarningIn("validTri(const triSurface&, const label)")
946 << "triangle " << faceI << " vertices " << f
947 << " uses point indices outside point range 0.."
948 << surf.points().size()-1 << endl;
953 if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
955 WarningIn("validTri(const triSurface&, const label)")
956 << "triangle " << faceI
957 << " uses non-unique vertices " << f
962 // duplicate triangle check
964 const labelList& fFaces = surf.faceFaces()[faceI];
966 // Check if faceNeighbours use same points as this face.
967 // Note: discards normal information - sides of baffle are merged.
970 label nbrFaceI = fFaces[i];
972 if (nbrFaceI <= faceI)
974 // lower numbered faces already checked
978 const labelledTri& nbrF = surf[nbrFaceI];
982 ((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
983 && ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
984 && ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
987 WarningIn("validTri(const triSurface&, const label)")
988 << "triangle " << faceI << " vertices " << f
989 << " has the same vertices as triangle " << nbrFaceI
990 << " vertices " << nbrF
1000 void Foam::isoSurfaceCell::calcAddressing
1002 const triSurface& surf,
1003 List<FixedList<label, 3> >& faceEdges,
1004 labelList& edgeFace0,
1005 labelList& edgeFace1,
1006 Map<labelList>& edgeFacesRest
1009 const pointField& points = surf.points();
1011 pointField edgeCentres(3*surf.size());
1015 const labelledTri& tri = surf[triI];
1016 edgeCentres[edgeI++] = 0.5*(points[tri[0]]+points[tri[1]]);
1017 edgeCentres[edgeI++] = 0.5*(points[tri[1]]+points[tri[2]]);
1018 edgeCentres[edgeI++] = 0.5*(points[tri[2]]+points[tri[0]]);
1021 pointField mergedCentres;
1022 labelList oldToMerged;
1023 bool hasMerged = mergePoints
1034 Pout<< "isoSurfaceCell : detected "
1035 << mergedCentres.size()
1036 << " edges on " << surf.size() << " triangles." << endl;
1041 if (surf.size() == 1)
1043 faceEdges.setSize(1);
1044 faceEdges[0][0] = 0;
1045 faceEdges[0][1] = 1;
1046 faceEdges[0][2] = 2;
1047 edgeFace0.setSize(1);
1049 edgeFace1.setSize(1);
1051 edgeFacesRest.clear();
1057 // Determine faceEdges
1058 faceEdges.setSize(surf.size());
1062 faceEdges[triI][0] = oldToMerged[edgeI++];
1063 faceEdges[triI][1] = oldToMerged[edgeI++];
1064 faceEdges[triI][2] = oldToMerged[edgeI++];
1068 // Determine edgeFaces
1069 edgeFace0.setSize(mergedCentres.size());
1071 edgeFace1.setSize(mergedCentres.size());
1073 edgeFacesRest.clear();
1075 forAll(oldToMerged, oldEdgeI)
1077 label triI = oldEdgeI / 3;
1078 label edgeI = oldToMerged[oldEdgeI];
1080 if (edgeFace0[edgeI] == -1)
1082 edgeFace0[edgeI] = triI;
1084 else if (edgeFace1[edgeI] == -1)
1086 edgeFace1[edgeI] = triI;
1090 //WarningIn("orientSurface(triSurface&)")
1091 // << "Edge " << edgeI << " with centre " << mergedCentres[edgeI]
1092 // << " used by more than two triangles: " << edgeFace0[edgeI]
1094 // << edgeFace1[edgeI] << " and " << triI << endl;
1095 Map<labelList>::iterator iter = edgeFacesRest.find(edgeI);
1097 if (iter != edgeFacesRest.end())
1099 labelList& eFaces = iter();
1100 label sz = eFaces.size();
1101 eFaces.setSize(sz+1);
1106 edgeFacesRest.insert(edgeI, labelList(1, triI));
1113 void Foam::isoSurfaceCell::walkOrientation
1115 const triSurface& surf,
1116 const List<FixedList<label, 3> >& faceEdges,
1117 const labelList& edgeFace0,
1118 const labelList& edgeFace1,
1119 const label seedTriI,
1120 labelList& flipState
1123 // Do walk for consistent orientation.
1124 DynamicList<label> changedFaces(surf.size());
1126 changedFaces.append(seedTriI);
1128 while (changedFaces.size())
1130 DynamicList<label> newChangedFaces(changedFaces.size());
1132 forAll(changedFaces, i)
1134 label triI = changedFaces[i];
1135 const labelledTri& tri = surf[triI];
1136 const FixedList<label, 3>& fEdges = faceEdges[triI];
1140 label edgeI = fEdges[fp];
1144 label p1 = tri[tri.fcIndex(fp)];
1148 edgeFace0[edgeI] != triI
1153 if (nbrI != -1 && flipState[nbrI] == -1)
1155 const labelledTri& nbrTri = surf[nbrI];
1158 label nbrFp = findIndex(nbrTri, p0);
1159 label nbrP1 = nbrTri[nbrTri.rcIndex(nbrFp)];
1161 bool sameOrientation = (p1 == nbrP1);
1163 if (flipState[triI] == 0)
1165 flipState[nbrI] = (sameOrientation ? 0 : 1);
1169 flipState[nbrI] = (sameOrientation ? 1 : 0);
1171 newChangedFaces.append(nbrI);
1176 changedFaces.transfer(newChangedFaces);
1181 void Foam::isoSurfaceCell::orientSurface
1184 const List<FixedList<label, 3> >& faceEdges,
1185 const labelList& edgeFace0,
1186 const labelList& edgeFace1,
1187 const Map<labelList>& edgeFacesRest
1193 labelList flipState(surf.size(), -1);
1199 // Find first unvisited triangle
1203 seedTriI < surf.size() && flipState[seedTriI] != -1;
1208 if (seedTriI == surf.size())
1213 // Note: Determine orientation of seedTriI?
1214 // for now assume it is ok
1215 flipState[seedTriI] = 0;
1228 // Do actual flipping
1232 if (flipState[triI] == 1)
1234 labelledTri tri(surf[triI]);
1236 surf[triI][0] = tri[0];
1237 surf[triI][1] = tri[2];
1238 surf[triI][2] = tri[1];
1240 else if (flipState[triI] == -1)
1244 "isoSurfaceCell::orientSurface(triSurface&, const label)"
1245 ) << "problem" << abort(FatalError);
1251 // Checks if triangle is connected through edgeI only.
1252 bool Foam::isoSurfaceCell::danglingTriangle
1254 const FixedList<label, 3>& fEdges,
1255 const labelList& edgeFace1
1261 if (edgeFace1[fEdges[i]] == -1)
1267 if (nOpen == 1 || nOpen == 2 || nOpen == 3)
1278 // Mark triangles to keep. Returns number of dangling triangles.
1279 Foam::label Foam::isoSurfaceCell::markDanglingTriangles
1281 const List<FixedList<label, 3> >& faceEdges,
1282 const labelList& edgeFace0,
1283 const labelList& edgeFace1,
1284 const Map<labelList>& edgeFacesRest,
1285 boolList& keepTriangles
1288 keepTriangles.setSize(faceEdges.size());
1289 keepTriangles = true;
1291 label nDangling = 0;
1293 // Remove any dangling triangles
1294 forAllConstIter(Map<labelList>, edgeFacesRest, iter)
1296 // These are all the non-manifold edges. Filter out all triangles
1297 // with only one connected edge (= this edge)
1299 label edgeI = iter.key();
1300 const labelList& otherEdgeFaces = iter();
1302 // Remove all dangling triangles
1303 if (danglingTriangle(faceEdges[edgeFace0[edgeI]], edgeFace1))
1305 keepTriangles[edgeFace0[edgeI]] = false;
1308 if (danglingTriangle(faceEdges[edgeFace1[edgeI]], edgeFace1))
1310 keepTriangles[edgeFace1[edgeI]] = false;
1313 forAll(otherEdgeFaces, i)
1315 label triI = otherEdgeFaces[i];
1316 if (danglingTriangle(faceEdges[triI], edgeFace1))
1318 keepTriangles[triI] = false;
1327 Foam::triSurface Foam::isoSurfaceCell::subsetMesh
1329 const triSurface& s,
1330 const labelList& newToOldFaces,
1331 labelList& oldToNewPoints,
1332 labelList& newToOldPoints
1335 const boolList include
1337 createWithValues<boolList>
1346 newToOldPoints.setSize(s.points().size());
1347 oldToNewPoints.setSize(s.points().size());
1348 oldToNewPoints = -1;
1352 forAll(include, oldFacei)
1354 if (include[oldFacei])
1356 // Renumber labels for triangle
1357 const labelledTri& tri = s[oldFacei];
1361 label oldPointI = tri[fp];
1363 if (oldToNewPoints[oldPointI] == -1)
1365 oldToNewPoints[oldPointI] = pointI;
1366 newToOldPoints[pointI++] = oldPointI;
1371 newToOldPoints.setSize(pointI);
1375 pointField newPoints(newToOldPoints.size());
1376 forAll(newToOldPoints, i)
1378 newPoints[i] = s.points()[newToOldPoints[i]];
1381 List<labelledTri> newTriangles(newToOldFaces.size());
1383 forAll(newToOldFaces, i)
1385 // Get old vertex labels
1386 const labelledTri& tri = s[newToOldFaces[i]];
1388 newTriangles[i][0] = oldToNewPoints[tri[0]];
1389 newTriangles[i][1] = oldToNewPoints[tri[1]];
1390 newTriangles[i][2] = oldToNewPoints[tri[2]];
1391 newTriangles[i].region() = tri.region();
1395 return triSurface(newTriangles, s.patches(), newPoints, true);
1399 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1401 Foam::isoSurfaceCell::isoSurfaceCell
1403 const polyMesh& mesh,
1404 const scalarField& cVals,
1405 const scalarField& pVals,
1407 const bool regularise,
1408 const scalar mergeTol
1413 mergeDistance_(mergeTol*mesh.bounds().mag())
1415 // Determine if cell is tet
1416 PackedBoolList isTet(mesh_.nCells());
1420 forAll(isTet, cellI)
1422 if (tet.isA(mesh_, cellI))
1424 isTet.set(cellI, 1);
1429 // Determine if point is on boundary. Points on boundaries are never
1430 // snapped. Coupled boundaries are handled explicitly so not marked here.
1431 PackedBoolList isBoundaryPoint(mesh_.nPoints());
1432 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1433 forAll(patches, patchI)
1435 const polyPatch& pp = patches[patchI];
1439 label faceI = pp.start();
1442 const face& f = mesh_.faces()[faceI++];
1446 isBoundaryPoint.set(f[fp], 1);
1453 // Determine if any cut through cell
1454 calcCutTypes(isTet, cVals, pVals);
1456 DynamicList<point> snappedPoints(nCutCells_);
1458 // Per cc -1 or a point inside snappedPoints.
1459 labelList snappedCc;
1473 snappedCc.setSize(mesh_.nCells());
1479 Pout<< "isoSurfaceCell : shifted " << snappedPoints.size()
1480 << " cell centres to intersection." << endl;
1483 snappedPoints.shrink();
1484 label nCellSnaps = snappedPoints.size();
1486 // Per point -1 or a point inside snappedPoints.
1487 labelList snappedPoint;
1502 snappedPoint.setSize(mesh_.nPoints());
1508 Pout<< "isoSurfaceCell : shifted " << snappedPoints.size()-nCellSnaps
1509 << " vertices to intersection." << endl;
1514 DynamicList<point> triPoints(nCutCells_);
1515 DynamicList<label> triMeshCells(nCutCells_);
1522 mesh_.cellCentres(),
1535 Pout<< "isoSurfaceCell : generated " << triMeshCells.size()
1536 << " unmerged triangles." << endl;
1539 // Merge points and compact out non-valid triangles
1540 labelList triMap; // merged to unmerged triangle
1541 triSurface::operator=
1545 true, // check for duplicate tris
1547 triPointMergeMap_, // unmerged to merged point
1554 Pout<< "isoSurfaceCell : generated " << triMap.size()
1555 << " merged triangles." << endl;
1558 meshCells_.setSize(triMap.size());
1561 meshCells_[i] = triMeshCells[triMap[i]];
1566 Pout<< "isoSurfaceCell : checking " << size()
1567 << " triangles for validity." << endl;
1571 // Copied from surfaceCheck
1572 validTri(*this, triI);
1579 List<FixedList<label, 3> > faceEdges;
1580 labelList edgeFace0, edgeFace1;
1581 Map<labelList> edgeFacesRest;
1586 // Calculate addressing
1587 calcAddressing(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
1589 // See if any dangling triangles
1590 boolList keepTriangles;
1591 label nDangling = markDanglingTriangles
1602 Pout<< "isoSurfaceCell : detected " << nDangling
1603 << " dangling triangles." << endl;
1611 // Create face map (new to old)
1612 labelList subsetTriMap(findIndices(keepTriangles, true));
1614 labelList subsetPointMap;
1615 labelList reversePointMap;
1616 triSurface::operator=
1626 meshCells_ = labelField(meshCells_, subsetTriMap);
1627 inplaceRenumber(reversePointMap, triPointMergeMap_);
1630 orientSurface(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
1633 //combineCellTriangles();
1638 //// Experimental retriangulation of triangles per cell. Problem is that
1639 //// -it is very expensive -only gets rid of internal points, not of boundary
1640 //// ones so limited benefit (e.g. 60 v.s. 88 triangles)
1641 //void Foam::isoSurfaceCell::combineCellTriangles()
1645 // DynamicList<labelledTri> newTris(size());
1646 // DynamicList<label> newTriToCell(size());
1648 // label startTriI = 0;
1650 // DynamicList<labelledTri> tris;
1652 // for (label triI = 1; triI <= meshCells_.size(); triI++)
1656 // triI == meshCells_.size()
1657 // || meshCells_[triI] != meshCells_[startTriI]
1660 // label nTris = triI-startTriI;
1664 // newTris.append(operator[](startTriI));
1665 // newTriToCell.append(meshCells_[startTriI]);
1669 // // Collect from startTriI to triI in a triSurface
1671 // for (label i = startTriI; i < triI; i++)
1673 // tris.append(operator[](i));
1675 // triSurface cellTris(tris, patches(), points());
1679 // const labelListList& loops = cellTris.edgeLoops();
1683 // // Do proper triangulation of loop
1684 // face loop(renumber(cellTris.meshPoints(), loops[i]));
1686 // faceTriangulation faceTris
1693 // // Copy into newTris
1694 // forAll(faceTris, faceTriI)
1696 // const triFace& tri = faceTris[faceTriI];
1705 // operator[](startTriI).region()
1708 // newTriToCell.append(meshCells_[startTriI]);
1713 // startTriI = triI;
1716 // newTris.shrink();
1717 // newTriToCell.shrink();
1720 // pointField newPoints(points().size());
1721 // label newPointI = 0;
1722 // labelList oldToNewPoint(points().size(), -1);
1724 // forAll(newTris, i)
1726 // labelledTri& tri = newTris[i];
1729 // label pointI = tri[j];
1731 // if (oldToNewPoint[pointI] == -1)
1733 // oldToNewPoint[pointI] = newPointI;
1734 // newPoints[newPointI++] = points()[pointI];
1736 // tri[j] = oldToNewPoint[pointI];
1739 // newPoints.setSize(newPointI);
1741 // triSurface::operator=
1751 // meshCells_.transfer(newTriToCell);
1756 // ************************************************************************* //