1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "isoSurfaceCell.H"
28 #include "dictionary.H"
30 #include "mergePoints.H"
31 #include "tetMatcher.H"
32 #include "syncTools.H"
33 #include "addToRunTimeSelectionTable.H"
34 #include "faceTriangulation.H"
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 defineTypeNameAndDebug(isoSurfaceCell, 0);
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 Foam::scalar Foam::isoSurfaceCell::isoFraction
64 //Foam::List<Foam::triFace> Foam::isoSurfaceCell::triangulate(const face& f)
67 // faceList triFaces(f.nTriangles(mesh_.points()));
68 // label triFaceI = 0;
69 // f.triangles(mesh_.points(), triFaceI, triFaces);
71 // List<triFace> tris(triFaces.size());
72 // forAll(triFaces, i)
74 // tris[i][0] = triFaces[i][0];
75 // tris[i][1] = triFaces[i][1];
76 // tris[i][2] = triFaces[i][2];
82 Foam::isoSurfaceCell::cellCutType Foam::isoSurfaceCell::calcCutType
84 const PackedBoolList& isTet,
85 const scalarField& cellValues,
86 const scalarField& pointValues,
90 const cell& cFaces = mesh_.cells()[cellI];
92 if (isTet.get(cellI) == 1)
94 forAll(cFaces, cFaceI)
96 const face& f = mesh_.faces()[cFaces[cFaceI]];
98 for (label fp = 1; fp < f.size() - 1; fp++)
100 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
102 bool aLower = (pointValues[tri[0]] < iso_);
103 bool bLower = (pointValues[tri[1]] < iso_);
104 bool cLower = (pointValues[tri[2]] < iso_);
106 if (aLower == bLower && aLower == cLower)
118 bool cellLower = (cellValues[cellI] < iso_);
120 // First check if there is any cut in cell
121 bool edgeCut = false;
123 forAll(cFaces, cFaceI)
125 const face& f = mesh_.faces()[cFaces[cFaceI]];
127 // Check pyramids cut
130 if ((pointValues[f[fp]] < iso_) != cellLower)
142 for (label fp = 1; fp < f.size() - 1; fp++)
144 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
145 //List<triFace> tris(triangulate(f));
148 // const triFace& tri = tris[i];
150 bool aLower = (pointValues[tri[0]] < iso_);
151 bool bLower = (pointValues[tri[1]] < iso_);
152 bool cLower = (pointValues[tri[2]] < iso_);
154 if (aLower == bLower && aLower == cLower)
171 // Count actual cuts (expensive since addressing needed)
172 // Note: not needed if you don't want to preserve maxima/minima
173 // centred around cellcentre. In that case just always return CUT
175 const labelList& cPoints = mesh_.cellPoints(cellI);
181 if ((pointValues[cPoints[i]] < iso_) != cellLower)
187 if (nPyrCuts == cPoints.size())
204 void Foam::isoSurfaceCell::calcCutTypes
206 const PackedBoolList& isTet,
207 const scalarField& cVals,
208 const scalarField& pVals
211 cellCutType_.setSize(mesh_.nCells());
213 forAll(mesh_.cells(), cellI)
215 cellCutType_[cellI] = calcCutType(isTet, cVals, pVals, cellI);
217 if (cellCutType_[cellI] == CUT)
225 Pout<< "isoSurfaceCell : detected " << nCutCells_
226 << " candidate cut cells." << endl;
232 // Return the two common points between two triangles
233 Foam::labelPair Foam::isoSurfaceCell::findCommonPoints
235 const labelledTri& tri0,
236 const labelledTri& tri1
239 labelPair common(-1, -1);
242 label fp1 = findIndex(tri1, tri0[fp0]);
247 fp1 = findIndex(tri1, tri0[fp0]);
252 // So tri0[fp0] is tri1[fp1]
254 // Find next common point
255 label fp0p1 = tri0.fcIndex(fp0);
256 label fp1p1 = tri1.fcIndex(fp1);
257 label fp1m1 = tri1.rcIndex(fp1);
259 if (tri0[fp0p1] == tri1[fp1p1] || tri0[fp0p1] == tri1[fp1m1])
261 common[0] = tri0[fp0];
262 common[1] = tri0[fp0p1];
269 // Caculate centre of surface.
270 Foam::point Foam::isoSurfaceCell::calcCentre(const triSurface& s)
272 vector sum = vector::zero;
276 sum += s[i].centre(s.points());
282 // Replace surface (localPoints, localTris) with single point. Returns
283 // point. Destructs arguments.
284 Foam::pointIndexHit Foam::isoSurfaceCell::collapseSurface
286 pointField& localPoints,
287 DynamicList<labelledTri, 64>& localTris
290 pointIndexHit info(false, vector::zero, localTris.size());
292 if (localTris.size() == 1)
294 const labelledTri& tri = localTris[0];
295 info.setPoint(tri.centre(localPoints));
298 else if (localTris.size() == 2)
300 // Check if the two triangles share an edge.
301 const labelledTri& tri0 = localTris[0];
302 const labelledTri& tri1 = localTris[0];
304 labelPair shared = findCommonPoints(tri0, tri1);
312 tri0.centre(localPoints)
313 + tri1.centre(localPoints)
319 else if (localTris.size())
321 // Check if single region. Rare situation.
325 geometricSurfacePatchList(0),
329 localTris.clearStorage();
332 label nZones = surf.markZones
334 boolList(surf.nEdges(), false),
340 info.setPoint(calcCentre(surf));
349 void Foam::isoSurfaceCell::calcSnappedCc
351 const PackedBoolList& isTet,
352 const scalarField& cVals,
353 const scalarField& pVals,
355 DynamicList<point>& snappedPoints,
359 const pointField& cc = mesh_.cellCentres();
360 const pointField& pts = mesh_.points();
362 snappedCc.setSize(mesh_.nCells());
366 DynamicList<point, 64> localPoints(64);
367 DynamicList<labelledTri, 64> localTris(64);
368 Map<label> pointToLocal(64);
370 forAll(mesh_.cells(), cellI)
372 if (cellCutType_[cellI] == CUT && isTet.get(cellI) == 0)
374 scalar cVal = cVals[cellI];
376 const cell& cFaces = mesh_.cells()[cellI];
380 pointToLocal.clear();
382 // Create points for all intersections close to cell centre
383 // (i.e. from pyramid edges)
385 forAll(cFaces, cFaceI)
387 const face& f = mesh_.faces()[cFaces[cFaceI]];
391 label pointI = f[fp];
393 scalar s = isoFraction(cVal, pVals[pointI]);
395 if (s >= 0.0 && s <= 0.5)
397 if (pointToLocal.insert(pointI, localPoints.size()))
399 localPoints.append((1.0-s)*cc[cellI]+s*pts[pointI]);
405 if (localPoints.size() == 1)
407 // No need for any analysis.
408 snappedCc[cellI] = snappedPoints.size();
409 snappedPoints.append(localPoints[0]);
411 //Pout<< "cell:" << cellI
412 // << " at " << mesh_.cellCentres()[cellI]
413 // << " collapsing " << localPoints
414 // << " intersections down to "
415 // << snappedPoints[snappedCc[cellI]] << endl;
417 else if (localPoints.size() == 2)
419 //? No need for any analysis.???
420 snappedCc[cellI] = snappedPoints.size();
421 snappedPoints.append(0.5*(localPoints[0]+localPoints[1]));
423 //Pout<< "cell:" << cellI
424 // << " at " << mesh_.cellCentres()[cellI]
425 // << " collapsing " << localPoints
426 // << " intersections down to "
427 // << snappedPoints[snappedCc[cellI]] << endl;
429 else if (localPoints.size())
432 forAll(cFaces, cFaceI)
434 const face& f = mesh_.faces()[cFaces[cFaceI]];
436 // Do a tetrahedrisation. Each face to cc becomes pyr.
437 // Each pyr gets split into tets by diagonalisation
440 for (label fp = 1; fp < f.size() - 1; fp++)
442 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
443 //List<triFace> tris(triangulate(f));
446 // const triFace& tri = tris[i];
448 // Get fractions for the three edges to cell centre
449 FixedList<scalar, 3> s(3);
450 s[0] = isoFraction(cVal, pVals[tri[0]]);
451 s[1] = isoFraction(cVal, pVals[tri[1]]);
452 s[2] = isoFraction(cVal, pVals[tri[2]]);
456 (s[0] >= 0.0 && s[0] <= 0.5)
457 && (s[1] >= 0.0 && s[1] <= 0.5)
458 && (s[2] >= 0.0 && s[2] <= 0.5)
465 pointToLocal[tri[0]],
466 pointToLocal[tri[1]],
467 pointToLocal[tri[2]],
475 pointField surfPoints;
476 surfPoints.transfer(localPoints);
477 pointIndexHit info = collapseSurface(surfPoints, localTris);
481 snappedCc[cellI] = snappedPoints.size();
482 snappedPoints.append(info.hitPoint());
484 //Pout<< "cell:" << cellI
485 // << " at " << mesh_.cellCentres()[cellI]
486 // << " collapsing " << surfPoints
487 // << " intersections down to "
488 // << snappedPoints[snappedCc[cellI]] << endl;
496 // Generate triangles for face connected to pointI
497 void Foam::isoSurfaceCell::genPointTris
499 const scalarField& cellValues,
500 const scalarField& pointValues,
504 DynamicList<point, 64>& localTriPoints
507 const pointField& cc = mesh_.cellCentres();
508 const pointField& pts = mesh_.points();
510 for (label fp = 1; fp < f.size() - 1; fp++)
512 triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
513 //List<triFace> tris(triangulate(f));
516 // const triFace& tri = tris[i];
518 label index = findIndex(tri, pointI);
525 // Tet between index..index-1, index..index+1, index..cc
526 label b = tri[tri.fcIndex(index)];
527 label c = tri[tri.rcIndex(index)];
529 // Get fractions for the three edges emanating from point
530 FixedList<scalar, 3> s(3);
531 s[0] = isoFraction(pointValues[pointI], pointValues[b]);
532 s[1] = isoFraction(pointValues[pointI], pointValues[c]);
533 s[2] = isoFraction(pointValues[pointI], cellValues[cellI]);
537 (s[0] >= 0.0 && s[0] <= 0.5)
538 && (s[1] >= 0.0 && s[1] <= 0.5)
539 && (s[2] >= 0.0 && s[2] <= 0.5)
542 localTriPoints.append((1.0-s[0])*pts[pointI] + s[0]*pts[b]);
543 localTriPoints.append((1.0-s[1])*pts[pointI] + s[1]*pts[c]);
544 localTriPoints.append((1.0-s[2])*pts[pointI] + s[2]*cc[cellI]);
550 // Generate triangle for tet connected to pointI
551 void Foam::isoSurfaceCell::genPointTris
553 const scalarField& pointValues,
556 DynamicList<point, 64>& localTriPoints
559 const pointField& pts = mesh_.points();
560 const cell& cFaces = mesh_.cells()[cellI];
562 FixedList<label, 4> tet;
564 label face0 = cFaces[0];
565 const face& f0 = mesh_.faces()[face0];
567 if (mesh_.faceOwner()[face0] != cellI)
580 // Find the point on the next face that is not on f0
581 const face& f1 = mesh_.faces()[cFaces[1]];
587 if (p1 != tet[0] && p1 != tet[1] && p1 != tet[2])
595 // Get the index of pointI
597 label i0 = findIndex(tet, pointI);
598 label i1 = tet.fcIndex(i0);
599 label i2 = tet.fcIndex(i1);
600 label i3 = tet.fcIndex(i2);
602 // Get fractions for the three edges emanating from point
603 FixedList<scalar, 3> s(3);
604 s[0] = isoFraction(pointValues[pointI], pointValues[tet[i1]]);
605 s[1] = isoFraction(pointValues[pointI], pointValues[tet[i2]]);
606 s[2] = isoFraction(pointValues[pointI], pointValues[tet[i3]]);
610 (s[0] >= 0.0 && s[0] <= 0.5)
611 && (s[1] >= 0.0 && s[1] <= 0.5)
612 && (s[2] >= 0.0 && s[2] <= 0.5)
615 localTriPoints.append((1.0-s[0])*pts[pointI] + s[0]*pts[tet[i1]]);
616 localTriPoints.append((1.0-s[1])*pts[pointI] + s[1]*pts[tet[i2]]);
617 localTriPoints.append((1.0-s[2])*pts[pointI] + s[2]*pts[tet[i3]]);
622 void Foam::isoSurfaceCell::calcSnappedPoint
624 const PackedBoolList& isBoundaryPoint,
625 const PackedBoolList& isTet,
626 const scalarField& cVals,
627 const scalarField& pVals,
629 DynamicList<point>& snappedPoints,
630 labelList& snappedPoint
633 const point greatPoint(VGREAT, VGREAT, VGREAT);
634 pointField collapsedPoint(mesh_.nPoints(), greatPoint);
638 DynamicList<point, 64> localTriPoints(100);
639 labelHashSet localPointCells(100);
641 forAll(mesh_.pointFaces(), pointI)
643 if (isBoundaryPoint.get(pointI) == 1)
648 const labelList& pFaces = mesh_.pointFaces()[pointI];
654 label faceI = pFaces[i];
658 cellCutType_[mesh_.faceOwner()[faceI]] == CUT
660 mesh_.isInternalFace(faceI)
661 && cellCutType_[mesh_.faceNeighbour()[faceI]] == CUT
676 localPointCells.clear();
677 localTriPoints.clear();
679 forAll(pFaces, pFaceI)
681 label faceI = pFaces[pFaceI];
682 const face& f = mesh_.faces()[faceI];
683 label own = mesh_.faceOwner()[faceI];
685 // Triangulate around f[0] on owner side
686 if (isTet.get(own) == 1)
688 if (localPointCells.insert(own))
690 genPointTris(pVals, pointI, own, localTriPoints);
695 genPointTris(cVals, pVals, pointI, f, own, localTriPoints);
698 if (mesh_.isInternalFace(faceI))
700 label nei = mesh_.faceNeighbour()[faceI];
702 if (isTet.get(nei) == 1)
704 if (localPointCells.insert(nei))
706 genPointTris(pVals, pointI, nei, localTriPoints);
711 genPointTris(cVals, pVals, pointI, f, nei, localTriPoints);
716 if (localTriPoints.size() == 3)
718 // Single triangle. No need for any analysis. Average points.
720 points.transfer(localTriPoints);
721 collapsedPoint[pointI] = sum(points)/points.size();
723 //Pout<< " point:" << pointI
724 // << " replacing coord:" << mesh_.points()[pointI]
725 // << " by average:" << collapsedPoint[pointI] << endl;
727 else if (localTriPoints.size())
729 // Convert points into triSurface.
731 // Merge points and compact out non-valid triangles
732 labelList triMap; // merged to unmerged triangle
733 labelList triPointReverseMap; // unmerged to merged point
738 false, // do not check for duplicate tris
746 label nZones = surf.markZones
748 boolList(surf.nEdges(), false),
754 collapsedPoint[pointI] = calcCentre(surf);
755 //Pout<< " point:" << pointI << " nZones:" << nZones
756 // << " replacing coord:" << mesh_.points()[pointI]
757 // << " by average:" << collapsedPoint[pointI] << endl;
762 syncTools::syncPointList
768 true // are coordinates so separate
771 snappedPoint.setSize(mesh_.nPoints());
774 forAll(collapsedPoint, pointI)
776 if (collapsedPoint[pointI] != greatPoint)
778 snappedPoint[pointI] = snappedPoints.size();
779 snappedPoints.append(collapsedPoint[pointI]);
787 Foam::triSurface Foam::isoSurfaceCell::stitchTriPoints
789 const bool checkDuplicates,
790 const List<point>& triPoints,
791 labelList& triPointReverseMap, // unmerged to merged point
792 labelList& triMap // merged to unmerged triangle
795 label nTris = triPoints.size()/3;
797 if ((triPoints.size() % 3) != 0)
799 FatalErrorIn("isoSurfaceCell::stitchTriPoints(..)")
800 << "Problem: number of points " << triPoints.size()
801 << " not a multiple of 3." << abort(FatalError);
804 pointField newPoints;
814 // Check that enough merged.
817 pointField newNewPoints;
819 bool hasMerged = mergePoints
830 FatalErrorIn("isoSurfaceCell::stitchTriPoints(..)")
831 << "Merged points contain duplicates"
832 << " when merging with distance " << mergeDistance_ << endl
833 << "merged:" << newPoints.size() << " re-merged:"
834 << newNewPoints.size()
835 << abort(FatalError);
840 List<labelledTri> tris;
842 DynamicList<labelledTri> dynTris(nTris);
844 DynamicList<label> newToOldTri(nTris);
846 for (label oldTriI = 0; oldTriI < nTris; oldTriI++)
850 triPointReverseMap[rawPointI],
851 triPointReverseMap[rawPointI+1],
852 triPointReverseMap[rawPointI+2],
857 if ((tri[0] != tri[1]) && (tri[0] != tri[2]) && (tri[1] != tri[2]))
859 newToOldTri.append(oldTriI);
864 triMap.transfer(newToOldTri);
865 tris.transfer(dynTris);
869 // Use face centres to determine 'flat hole' situation (see RMT paper).
870 // Two unconnected triangles get connected because (some of) the edges
871 // separating them get collapsed. Below only checks for duplicate triangles,
872 // not non-manifold edge connectivity.
877 Pout<< "isoSurfaceCell : merged from " << nTris
878 << " down to " << tris.size() << " triangles." << endl;
881 pointField centres(tris.size());
884 centres[triI] = tris[triI].centre(newPoints);
887 pointField mergedCentres;
888 labelList oldToMerged;
889 bool hasMerged = mergePoints
900 Pout<< "isoSurfaceCell : detected "
901 << centres.size()-mergedCentres.size()
902 << " duplicate triangles." << endl;
907 // Filter out duplicates.
909 DynamicList<label> newToOldTri(tris.size());
910 labelList newToMaster(mergedCentres.size(), -1);
913 label mergedI = oldToMerged[triI];
915 if (newToMaster[mergedI] == -1)
917 newToMaster[mergedI] = triI;
918 newToOldTri.append(triMap[triI]);
919 tris[newTriI++] = tris[triI];
923 triMap.transfer(newToOldTri);
924 tris.setSize(newTriI);
928 return triSurface(tris, geometricSurfacePatchList(0), newPoints, true);
932 // Does face use valid vertices?
933 bool Foam::isoSurfaceCell::validTri(const triSurface& surf, const label faceI)
935 // Simple check on indices ok.
937 const labelledTri& f = surf[faceI];
941 (f[0] < 0) || (f[0] >= surf.points().size())
942 || (f[1] < 0) || (f[1] >= surf.points().size())
943 || (f[2] < 0) || (f[2] >= surf.points().size())
946 WarningIn("validTri(const triSurface&, const label)")
947 << "triangle " << faceI << " vertices " << f
948 << " uses point indices outside point range 0.."
949 << surf.points().size()-1 << endl;
954 if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
956 WarningIn("validTri(const triSurface&, const label)")
957 << "triangle " << faceI
958 << " uses non-unique vertices " << f
963 // duplicate triangle check
965 const labelList& fFaces = surf.faceFaces()[faceI];
967 // Check if faceNeighbours use same points as this face.
968 // Note: discards normal information - sides of baffle are merged.
971 label nbrFaceI = fFaces[i];
973 if (nbrFaceI <= faceI)
975 // lower numbered faces already checked
979 const labelledTri& nbrF = surf[nbrFaceI];
983 ((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
984 && ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
985 && ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
988 WarningIn("validTri(const triSurface&, const label)")
989 << "triangle " << faceI << " vertices " << f
990 << " has the same vertices as triangle " << nbrFaceI
991 << " vertices " << nbrF
1001 void Foam::isoSurfaceCell::calcAddressing
1003 const triSurface& surf,
1004 List<FixedList<label, 3> >& faceEdges,
1005 labelList& edgeFace0,
1006 labelList& edgeFace1,
1007 Map<labelList>& edgeFacesRest
1010 const pointField& points = surf.points();
1012 pointField edgeCentres(3*surf.size());
1016 const labelledTri& tri = surf[triI];
1017 edgeCentres[edgeI++] = 0.5*(points[tri[0]]+points[tri[1]]);
1018 edgeCentres[edgeI++] = 0.5*(points[tri[1]]+points[tri[2]]);
1019 edgeCentres[edgeI++] = 0.5*(points[tri[2]]+points[tri[0]]);
1022 pointField mergedCentres;
1023 labelList oldToMerged;
1024 bool hasMerged = mergePoints
1035 Pout<< "isoSurfaceCell : detected "
1036 << mergedCentres.size()
1037 << " edges on " << surf.size() << " triangles." << endl;
1042 if (surf.size() == 1)
1044 faceEdges.setSize(1);
1045 faceEdges[0][0] = 0;
1046 faceEdges[0][1] = 1;
1047 faceEdges[0][2] = 2;
1048 edgeFace0.setSize(1);
1050 edgeFace1.setSize(1);
1052 edgeFacesRest.clear();
1058 // Determine faceEdges
1059 faceEdges.setSize(surf.size());
1063 faceEdges[triI][0] = oldToMerged[edgeI++];
1064 faceEdges[triI][1] = oldToMerged[edgeI++];
1065 faceEdges[triI][2] = oldToMerged[edgeI++];
1069 // Determine edgeFaces
1070 edgeFace0.setSize(mergedCentres.size());
1072 edgeFace1.setSize(mergedCentres.size());
1074 edgeFacesRest.clear();
1076 forAll(oldToMerged, oldEdgeI)
1078 label triI = oldEdgeI / 3;
1079 label edgeI = oldToMerged[oldEdgeI];
1081 if (edgeFace0[edgeI] == -1)
1083 edgeFace0[edgeI] = triI;
1085 else if (edgeFace1[edgeI] == -1)
1087 edgeFace1[edgeI] = triI;
1091 //WarningIn("orientSurface(triSurface&)")
1092 // << "Edge " << edgeI << " with centre " << mergedCentres[edgeI]
1093 // << " used by more than two triangles: " << edgeFace0[edgeI]
1095 // << edgeFace1[edgeI] << " and " << triI << endl;
1096 Map<labelList>::iterator iter = edgeFacesRest.find(edgeI);
1098 if (iter != edgeFacesRest.end())
1100 labelList& eFaces = iter();
1101 label sz = eFaces.size();
1102 eFaces.setSize(sz+1);
1107 edgeFacesRest.insert(edgeI, labelList(1, triI));
1114 void Foam::isoSurfaceCell::walkOrientation
1116 const triSurface& surf,
1117 const List<FixedList<label, 3> >& faceEdges,
1118 const labelList& edgeFace0,
1119 const labelList& edgeFace1,
1120 const label seedTriI,
1121 labelList& flipState
1124 // Do walk for consistent orientation.
1125 DynamicList<label> changedFaces(surf.size());
1127 changedFaces.append(seedTriI);
1129 while (changedFaces.size())
1131 DynamicList<label> newChangedFaces(changedFaces.size());
1133 forAll(changedFaces, i)
1135 label triI = changedFaces[i];
1136 const labelledTri& tri = surf[triI];
1137 const FixedList<label, 3>& fEdges = faceEdges[triI];
1141 label edgeI = fEdges[fp];
1145 label p1 = tri[tri.fcIndex(fp)];
1149 edgeFace0[edgeI] != triI
1154 if (nbrI != -1 && flipState[nbrI] == -1)
1156 const labelledTri& nbrTri = surf[nbrI];
1159 label nbrFp = findIndex(nbrTri, p0);
1160 label nbrP1 = nbrTri[nbrTri.rcIndex(nbrFp)];
1162 bool sameOrientation = (p1 == nbrP1);
1164 if (flipState[triI] == 0)
1166 flipState[nbrI] = (sameOrientation ? 0 : 1);
1170 flipState[nbrI] = (sameOrientation ? 1 : 0);
1172 newChangedFaces.append(nbrI);
1177 changedFaces.transfer(newChangedFaces);
1182 void Foam::isoSurfaceCell::orientSurface
1185 const List<FixedList<label, 3> >& faceEdges,
1186 const labelList& edgeFace0,
1187 const labelList& edgeFace1,
1188 const Map<labelList>& edgeFacesRest
1194 labelList flipState(surf.size(), -1);
1200 // Find first unvisited triangle
1204 seedTriI < surf.size() && flipState[seedTriI] != -1;
1209 if (seedTriI == surf.size())
1214 // Note: Determine orientation of seedTriI?
1215 // for now assume it is ok
1216 flipState[seedTriI] = 0;
1229 // Do actual flipping
1233 if (flipState[triI] == 1)
1235 labelledTri tri(surf[triI]);
1237 surf[triI][0] = tri[0];
1238 surf[triI][1] = tri[2];
1239 surf[triI][2] = tri[1];
1241 else if (flipState[triI] == -1)
1245 "isoSurfaceCell::orientSurface(triSurface&, const label)"
1246 ) << "problem" << abort(FatalError);
1252 // Checks if triangle is connected through edgeI only.
1253 bool Foam::isoSurfaceCell::danglingTriangle
1255 const FixedList<label, 3>& fEdges,
1256 const labelList& edgeFace1
1262 if (edgeFace1[fEdges[i]] == -1)
1268 if (nOpen == 1 || nOpen == 2 || nOpen == 3)
1279 // Mark triangles to keep. Returns number of dangling triangles.
1280 Foam::label Foam::isoSurfaceCell::markDanglingTriangles
1282 const List<FixedList<label, 3> >& faceEdges,
1283 const labelList& edgeFace0,
1284 const labelList& edgeFace1,
1285 const Map<labelList>& edgeFacesRest,
1286 boolList& keepTriangles
1289 keepTriangles.setSize(faceEdges.size());
1290 keepTriangles = true;
1292 label nDangling = 0;
1294 // Remove any dangling triangles
1295 forAllConstIter(Map<labelList>, edgeFacesRest, iter)
1297 // These are all the non-manifold edges. Filter out all triangles
1298 // with only one connected edge (= this edge)
1300 label edgeI = iter.key();
1301 const labelList& otherEdgeFaces = iter();
1303 // Remove all dangling triangles
1304 if (danglingTriangle(faceEdges[edgeFace0[edgeI]], edgeFace1))
1306 keepTriangles[edgeFace0[edgeI]] = false;
1309 if (danglingTriangle(faceEdges[edgeFace1[edgeI]], edgeFace1))
1311 keepTriangles[edgeFace1[edgeI]] = false;
1314 forAll(otherEdgeFaces, i)
1316 label triI = otherEdgeFaces[i];
1317 if (danglingTriangle(faceEdges[triI], edgeFace1))
1319 keepTriangles[triI] = false;
1328 Foam::triSurface Foam::isoSurfaceCell::subsetMesh
1330 const triSurface& s,
1331 const labelList& newToOldFaces,
1332 labelList& oldToNewPoints,
1333 labelList& newToOldPoints
1336 const boolList include
1338 createWithValues<boolList>
1347 newToOldPoints.setSize(s.points().size());
1348 oldToNewPoints.setSize(s.points().size());
1349 oldToNewPoints = -1;
1353 forAll(include, oldFacei)
1355 if (include[oldFacei])
1357 // Renumber labels for triangle
1358 const labelledTri& tri = s[oldFacei];
1362 label oldPointI = tri[fp];
1364 if (oldToNewPoints[oldPointI] == -1)
1366 oldToNewPoints[oldPointI] = pointI;
1367 newToOldPoints[pointI++] = oldPointI;
1372 newToOldPoints.setSize(pointI);
1376 pointField newPoints(newToOldPoints.size());
1377 forAll(newToOldPoints, i)
1379 newPoints[i] = s.points()[newToOldPoints[i]];
1382 List<labelledTri> newTriangles(newToOldFaces.size());
1384 forAll(newToOldFaces, i)
1386 // Get old vertex labels
1387 const labelledTri& tri = s[newToOldFaces[i]];
1389 newTriangles[i][0] = oldToNewPoints[tri[0]];
1390 newTriangles[i][1] = oldToNewPoints[tri[1]];
1391 newTriangles[i][2] = oldToNewPoints[tri[2]];
1392 newTriangles[i].region() = tri.region();
1396 return triSurface(newTriangles, s.patches(), newPoints, true);
1400 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1402 Foam::isoSurfaceCell::isoSurfaceCell
1404 const polyMesh& mesh,
1405 const scalarField& cVals,
1406 const scalarField& pVals,
1408 const bool regularise,
1409 const scalar mergeTol
1414 mergeDistance_(mergeTol*mesh.bounds().mag())
1416 // Determine if cell is tet
1417 PackedBoolList isTet(mesh_.nCells());
1421 forAll(isTet, cellI)
1423 if (tet.isA(mesh_, cellI))
1425 isTet.set(cellI, 1);
1430 // Determine if point is on boundary. Points on boundaries are never
1431 // snapped. Coupled boundaries are handled explicitly so not marked here.
1432 PackedBoolList isBoundaryPoint(mesh_.nPoints());
1433 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1434 forAll(patches, patchI)
1436 const polyPatch& pp = patches[patchI];
1440 label faceI = pp.start();
1443 const face& f = mesh_.faces()[faceI++];
1447 isBoundaryPoint.set(f[fp], 1);
1454 // Determine if any cut through cell
1455 calcCutTypes(isTet, cVals, pVals);
1457 DynamicList<point> snappedPoints(nCutCells_);
1459 // Per cc -1 or a point inside snappedPoints.
1460 labelList snappedCc;
1474 snappedCc.setSize(mesh_.nCells());
1480 Pout<< "isoSurfaceCell : shifted " << snappedPoints.size()
1481 << " cell centres to intersection." << endl;
1484 snappedPoints.shrink();
1485 label nCellSnaps = snappedPoints.size();
1487 // Per point -1 or a point inside snappedPoints.
1488 labelList snappedPoint;
1503 snappedPoint.setSize(mesh_.nPoints());
1509 Pout<< "isoSurfaceCell : shifted " << snappedPoints.size()-nCellSnaps
1510 << " vertices to intersection." << endl;
1515 DynamicList<point> triPoints(nCutCells_);
1516 DynamicList<label> triMeshCells(nCutCells_);
1523 mesh_.cellCentres(),
1536 Pout<< "isoSurfaceCell : generated " << triMeshCells.size()
1537 << " unmerged triangles." << endl;
1540 // Merge points and compact out non-valid triangles
1541 labelList triMap; // merged to unmerged triangle
1542 triSurface::operator=
1546 true, // check for duplicate tris
1548 triPointMergeMap_, // unmerged to merged point
1555 Pout<< "isoSurfaceCell : generated " << triMap.size()
1556 << " merged triangles." << endl;
1559 meshCells_.setSize(triMap.size());
1562 meshCells_[i] = triMeshCells[triMap[i]];
1567 Pout<< "isoSurfaceCell : checking " << size()
1568 << " triangles for validity." << endl;
1572 // Copied from surfaceCheck
1573 validTri(*this, triI);
1580 List<FixedList<label, 3> > faceEdges;
1581 labelList edgeFace0, edgeFace1;
1582 Map<labelList> edgeFacesRest;
1587 // Calculate addressing
1588 calcAddressing(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
1590 // See if any dangling triangles
1591 boolList keepTriangles;
1592 label nDangling = markDanglingTriangles
1603 Pout<< "isoSurfaceCell : detected " << nDangling
1604 << " dangling triangles." << endl;
1612 // Create face map (new to old)
1613 labelList subsetTriMap(findIndices(keepTriangles, true));
1615 labelList subsetPointMap;
1616 labelList reversePointMap;
1617 triSurface::operator=
1627 meshCells_ = labelField(meshCells_, subsetTriMap);
1628 inplaceRenumber(reversePointMap, triPointMergeMap_);
1631 orientSurface(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
1634 //combineCellTriangles();
1639 //// Experimental retriangulation of triangles per cell. Problem is that
1640 //// -it is very expensive -only gets rid of internal points, not of boundary
1641 //// ones so limited benefit (e.g. 60 v.s. 88 triangles)
1642 //void Foam::isoSurfaceCell::combineCellTriangles()
1646 // DynamicList<labelledTri> newTris(size());
1647 // DynamicList<label> newTriToCell(size());
1649 // label startTriI = 0;
1651 // DynamicList<labelledTri> tris;
1653 // for (label triI = 1; triI <= meshCells_.size(); triI++)
1657 // triI == meshCells_.size()
1658 // || meshCells_[triI] != meshCells_[startTriI]
1661 // label nTris = triI-startTriI;
1665 // newTris.append(operator[](startTriI));
1666 // newTriToCell.append(meshCells_[startTriI]);
1670 // // Collect from startTriI to triI in a triSurface
1672 // for (label i = startTriI; i < triI; i++)
1674 // tris.append(operator[](i));
1676 // triSurface cellTris(tris, patches(), points());
1680 // const labelListList& loops = cellTris.edgeLoops();
1684 // // Do proper triangulation of loop
1685 // face loop(renumber(cellTris.meshPoints(), loops[i]));
1687 // faceTriangulation faceTris
1694 // // Copy into newTris
1695 // forAll(faceTris, faceTriI)
1697 // const triFace& tri = faceTris[faceTriI];
1706 // operator[](startTriI).region()
1709 // newTriToCell.append(meshCells_[startTriI]);
1714 // startTriI = triI;
1717 // newTris.shrink();
1718 // newTriToCell.shrink();
1721 // pointField newPoints(points().size());
1722 // label newPointI = 0;
1723 // labelList oldToNewPoint(points().size(), -1);
1725 // forAll(newTris, i)
1727 // labelledTri& tri = newTris[i];
1730 // label pointI = tri[j];
1732 // if (oldToNewPoint[pointI] == -1)
1734 // oldToNewPoint[pointI] = newPointI;
1735 // newPoints[newPointI++] = points()[pointI];
1737 // tri[j] = oldToNewPoint[pointI];
1740 // newPoints.setSize(newPointI);
1742 // triSurface::operator=
1752 // meshCells_.transfer(newTriToCell);
1757 // ************************************************************************* //