BUGFIX: Uninitialised member variables
[foam-extend-3.2.git] / applications / utilities / surface / surfaceToPatch / boundaryMesh.C
blob2263212e0c504d7ea9f2b38e1567887eaeb472d2
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright held by original author
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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
19     for more details.
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 "boundaryMesh.H"
28 #include "objectRegistry.H"
29 #include "Time.H"
30 #include "polyMesh.H"
31 #include "repatchPolyTopoChanger.H"
32 #include "faceList.H"
33 #include "indexedOctree.H"
34 #include "treeDataPrimitivePatch.H"
35 #include "triSurface.H"
36 #include "SortableList.H"
37 #include "OFstream.H"
38 #include "uindirectPrimitivePatch.H"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 defineTypeNameAndDebug(Foam::boundaryMesh, 0);
44 // Normal along which to divide faces into categories (used in getNearest)
45 const Foam::vector Foam::boundaryMesh::splitNormal_(3, 2, 1);
47 // Distance to face tolerance for getNearest
48 const Foam::scalar Foam::boundaryMesh::distanceTol_ = 1E-2;
51 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
53 // Returns number of feature edges connected to pointI
54 Foam::label Foam::boundaryMesh::nFeatureEdges(label pointI) const
56     label nFeats = 0;
58     const labelList& pEdges = mesh().pointEdges()[pointI];
60     forAll(pEdges, pEdgeI)
61     {
62         label edgeI = pEdges[pEdgeI];
64         if (edgeToFeature_[edgeI] != -1)
65         {
66             nFeats++;
67         }
68     }
69     return nFeats;
73 // Returns next feature edge connected to pointI
74 Foam::label Foam::boundaryMesh::nextFeatureEdge
76     const label edgeI,
77     const label vertI
78 ) const
80     const labelList& pEdges = mesh().pointEdges()[vertI];
82     forAll(pEdges, pEdgeI)
83     {
84         label nbrEdgeI = pEdges[pEdgeI];
86         if (nbrEdgeI != edgeI)
87         {
88             label featI = edgeToFeature_[nbrEdgeI];
90             if (featI != -1)
91             {
92                 return nbrEdgeI;
93             }
94         }
95     }
97     return -1;
101 // Finds connected feature edges, starting from startPointI and returns
102 // feature labels (not edge labels). Marks feature edges handled in
103 // featVisited.
104 Foam::labelList Foam::boundaryMesh::collectSegment
106     const boolList& isFeaturePoint,
107     const label startEdgeI,
108     boolList& featVisited
109 ) const
111     // Find starting feature point on edge.
113     label edgeI = startEdgeI;
115     const edge& e = mesh().edges()[edgeI];
117     label vertI = e.start();
119     while (!isFeaturePoint[vertI])
120     {
121         // Step to next feature edge
123         edgeI = nextFeatureEdge(edgeI, vertI);
125         if ((edgeI == -1) || (edgeI == startEdgeI))
126         {
127             break;
128         }
130         // Step to next vertex on edge
132         const edge& e = mesh().edges()[edgeI];
134         vertI = e.otherVertex(vertI);
135     }
137     //
138     // Now we have:
139     //    edgeI : first edge on this segment
140     //    vertI : one of the endpoints of this segment
141     //
142     // Start walking other way and storing edges as we go along.
143     //
145     // Untrimmed storage for current segment
146     labelList featLabels(featureEdges_.size());
148     label featLabelI = 0;
150     label initEdgeI = edgeI;
152     do
153     {
154         // Mark edge as visited
155         label featI = edgeToFeature_[edgeI];
157         if (featI == -1)
158         {
159             FatalErrorIn("boundaryMesh::collectSegment")
160                 << "Problem" << abort(FatalError);
161         }
162         featLabels[featLabelI++] = featI;
164         featVisited[featI] = true;
166         // Step to next vertex on edge
168         const edge& e = mesh().edges()[edgeI];
170         vertI = e.otherVertex(vertI);
172         // Step to next feature edge
174         edgeI = nextFeatureEdge(edgeI, vertI);
176         if ((edgeI == -1) || (edgeI == initEdgeI))
177         {
178             break;
179         }
180     }
181     while (!isFeaturePoint[vertI]);
184     // Trim to size
185     featLabels.setSize(featLabelI);
187     return featLabels;
191 void Foam::boundaryMesh::markEdges
193     const label maxDistance,
194     const label edgeI,
195     const label distance,
196     labelList& minDistance,
197     DynamicList<label>& visited
198 ) const
200     if (distance < maxDistance)
201     {
202         // Don't do anything if reached beyond maxDistance.
204         if (minDistance[edgeI] == -1)
205         {
206             // First visit of edge. Store edge label.
207             visited.append(edgeI);
208         }
209         else if (minDistance[edgeI] <= distance)
210         {
211             // Already done this edge
212             return;
213         }
215         minDistance[edgeI] = distance;
217         const edge& e = mesh().edges()[edgeI];
219         // Do edges connected to e.start
220         const labelList& startEdges = mesh().pointEdges()[e.start()];
222         forAll(startEdges, pEdgeI)
223         {
224             markEdges
225             (
226                 maxDistance,
227                 startEdges[pEdgeI],
228                 distance+1,
229                 minDistance,
230                 visited
231             );
232         }
234         // Do edges connected to e.end
235         const labelList& endEdges = mesh().pointEdges()[e.end()];
237         forAll(endEdges, pEdgeI)
238         {
239             markEdges
240             (
241                 maxDistance,
242                 endEdges[pEdgeI],
243                 distance+1,
244                 minDistance,
245                 visited
246             );
247         }
248     }
252 Foam::label Foam::boundaryMesh::findPatchID
254     const polyPatchList& patches,
255     const word& patchName
256 ) const
258     forAll(patches, patchI)
259     {
260         if (patches[patchI].name() == patchName)
261         {
262             return patchI;
263         }
264     }
266     return -1;
270 Foam::wordList Foam::boundaryMesh::patchNames() const
272     wordList names(patches_.size());
274     forAll(patches_, patchI)
275     {
276         names[patchI] = patches_[patchI].name();
277     }
278     return names;
282 Foam::label Foam::boundaryMesh::whichPatch
284     const polyPatchList& patches,
285     const label faceI
286 ) const
288     forAll(patches, patchI)
289     {
290         const polyPatch& pp = patches[patchI];
292         if ((faceI >= pp.start()) && (faceI < (pp.start() + pp.size())))
293         {
294             return patchI;
295         }
296     }
297     return -1;
301 // Gets labels of changed faces and propagates them to the edges. Returns
302 // labels of edges changed.
303 Foam::labelList Foam::boundaryMesh::faceToEdge
305     const boolList& regionEdge,
306     const label region,
307     const labelList& changedFaces,
308     labelList& edgeRegion
309 ) const
311     labelList changedEdges(mesh().nEdges(), -1);
312     label changedI = 0;
314     forAll(changedFaces, i)
315     {
316         label faceI = changedFaces[i];
318         const labelList& fEdges = mesh().faceEdges()[faceI];
320         forAll(fEdges, fEdgeI)
321         {
322             label edgeI = fEdges[fEdgeI];
324             if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
325             {
326                 edgeRegion[edgeI] = region;
328                 changedEdges[changedI++] = edgeI;
329             }
330         }
331     }
333     changedEdges.setSize(changedI);
335     return changedEdges;
339 // Reverse of faceToEdge: gets edges and returns faces
340 Foam::labelList Foam::boundaryMesh::edgeToFace
342     const label region,
343     const labelList& changedEdges,
344     labelList& faceRegion
345 ) const
347     labelList changedFaces(mesh().size(), -1);
348     label changedI = 0;
350     forAll(changedEdges, i)
351     {
352         label edgeI = changedEdges[i];
354         const labelList& eFaces = mesh().edgeFaces()[edgeI];
356         forAll(eFaces, eFaceI)
357         {
358             label faceI = eFaces[eFaceI];
360             if (faceRegion[faceI] == -1)
361             {
362                 faceRegion[faceI] = region;
364                 changedFaces[changedI++] = faceI;
365             }
366         }
367     }
369     changedFaces.setSize(changedI);
371     return changedFaces;
375 // Finds area, starting at faceI, delimited by borderEdge
376 void Foam::boundaryMesh::markZone
378     const boolList& borderEdge,
379     label faceI,
380     label currentZone,
381     labelList& faceZone
382 ) const
384     faceZone[faceI] = currentZone;
386     // List of faces whose faceZone has been set.
387     labelList changedFaces(1, faceI);
388     // List of edges whose faceZone has been set.
389     labelList changedEdges;
391     // Zones on all edges.
392     labelList edgeZone(mesh().nEdges(), -1);
394     while(1)
395     {
396         changedEdges = faceToEdge
397         (
398             borderEdge,
399             currentZone,
400             changedFaces,
401             edgeZone
402         );
404         if (debug)
405         {
406             Pout<< "From changedFaces:" << changedFaces.size()
407                 << " to changedEdges:" << changedEdges.size()
408                 << endl;
409         }
411         if (changedEdges.empty())
412         {
413             break;
414         }
416         changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
418         if (debug)
419         {
420             Pout<< "From changedEdges:" << changedEdges.size()
421                 << " to changedFaces:" << changedFaces.size()
422                 << endl;
423         }
425         if (changedFaces.empty())
426         {
427             break;
428         }
429     }
433 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
435 // Null constructor
436 Foam::boundaryMesh::boundaryMesh()
438     meshPtr_(NULL),
439     patches_(),
440     meshFace_(),
441     featurePoints_(),
442     featureEdges_(),
443     featureToEdge_(),
444     edgeToFeature_(),
445     featureSegments_(),
446     extraEdges_()
450 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
452 Foam::boundaryMesh::~boundaryMesh()
454     clearOut();
458 void Foam::boundaryMesh::clearOut()
460     if (meshPtr_)
461     {
462         delete meshPtr_;
464         meshPtr_ = NULL;
465     }
469 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
471 void Foam::boundaryMesh::read(const polyMesh& mesh)
473     patches_.clear();
475     patches_.setSize(mesh.boundaryMesh().size());
477     // Number of boundary faces
478     label nBFaces = mesh.nFaces() - mesh.nInternalFaces();
480     faceList bFaces(nBFaces);
482     meshFace_.setSize(nBFaces);
484     label bFaceI = 0;
486     // Collect all boundary faces.
487     forAll(mesh.boundaryMesh(), patchI)
488     {
489         const polyPatch& pp = mesh.boundaryMesh()[patchI];
491         patches_.set
492         (
493             patchI,
494             new boundaryPatch
495             (
496                 pp.name(),
497                 patchI,
498                 pp.size(),
499                 bFaceI,
500                 pp.type()
501             )
502         );
504         // Collect all faces in global numbering.
505         forAll(pp, patchFaceI)
506         {
507             meshFace_[bFaceI] = pp.start() + patchFaceI;
509             bFaces[bFaceI] = pp[patchFaceI];
511             bFaceI++;
512         }
513     }
516     if (debug)
517     {
518         Pout<< "read : patches now:" << endl;
520         forAll(patches_, patchI)
521         {
522             const boundaryPatch& bp = patches_[patchI];
524             Pout<< "    name  : " << bp.name() << endl
525                 << "    size  : " << bp.size() << endl
526                 << "    start : " << bp.start() << endl
527                 << "    type  : " << bp.physicalType() << endl
528                 << endl;
529         }
530     }
532     //
533     // Construct single patch for all of boundary
534     //
536     // Temporary primitivePatch to calculate compact points & faces.
537     PrimitivePatch<face, List, const pointField&> globalPatch
538     (
539         bFaces,
540         mesh.points()
541     );
543     // Store in local(compact) addressing
544     clearOut();
546     meshPtr_ = new bMesh(globalPatch.localFaces(), globalPatch.localPoints());
549     if (debug & 2)
550     {
551         const bMesh& msh = *meshPtr_;
553         Pout<< "** Start of Faces **" << endl;
555         forAll(msh, faceI)
556         {
557             const face& f = msh[faceI];
559             point ctr(vector::zero);
561             forAll(f, fp)
562             {
563                 ctr += msh.points()[f[fp]];
564             }
565             ctr /= f.size();
567             Pout<< "    " << faceI
568                 << " ctr:" << ctr
569                 << " verts:" << f
570                 << endl;
571         }
573         Pout<< "** End of Faces **" << endl;
575         Pout<< "** Start of Points **" << endl;
577         forAll(msh.points(), pointI)
578         {
579             Pout<< "    " << pointI
580                 << " coord:" << msh.points()[pointI]
581                 << endl;
582         }
584         Pout<< "** End of Points **" << endl;
585     }
587     // Clear edge storage
588     featurePoints_.setSize(0);
589     featureEdges_.setSize(0);
591     featureToEdge_.setSize(0);
592     edgeToFeature_.setSize(meshPtr_->nEdges());
593     edgeToFeature_ = -1;
595     featureSegments_.setSize(0);
597     extraEdges_.setSize(0);
601 void Foam::boundaryMesh::readTriSurface(const fileName& fName)
603     triSurface surf(fName);
605     if (surf.empty())
606     {
607         return;
608     }
610     // Sort according to region
611     SortableList<label> regions(surf.size());
613     forAll(surf, triI)
614     {
615         regions[triI] = surf[triI].region();
616     }
617     regions.sort();
619     // Determine region mapping.
620     Map<label> regionToBoundaryPatch;
622     label oldRegion = -1111;
623     label boundPatch = 0;
625     forAll(regions, i)
626     {
627         if (regions[i] != oldRegion)
628         {
629             regionToBoundaryPatch.insert(regions[i], boundPatch);
631             oldRegion = regions[i];
632             boundPatch++;
633         }
634     }
636     const geometricSurfacePatchList& surfPatches = surf.patches();
638     patches_.clear();
640     if (surfPatches.size() == regionToBoundaryPatch.size())
641     {
642         // There are as many surface patches as region numbers in triangles
643         // so use the surface patches
645         patches_.setSize(surfPatches.size());
647         // Take over patches, setting size to 0 for now.
648         forAll(surfPatches, patchI)
649         {
650             const geometricSurfacePatch& surfPatch = surfPatches[patchI];
652             patches_.set
653             (
654                 patchI,
655                 new boundaryPatch
656                 (
657                     surfPatch.name(),
658                     patchI,
659                     0,
660                     0,
661                     surfPatch.geometricType()
662                 )
663             );
664         }
665     }
666     else
667     {
668         // There are not enough surface patches. Make up my own.
670         patches_.setSize(regionToBoundaryPatch.size());
672         forAll(patches_, patchI)
673         {
674             patches_.set
675             (
676                 patchI,
677                 new boundaryPatch
678                 (
679                     "patch" + name(patchI),
680                     patchI,
681                     0,
682                     0,
683                     "empty"
684                 )
685             );
686         }
687     }
689     //
690     // Copy according into bFaces according to regions
691     //
693     const labelList& indices = regions.indices();
695     faceList bFaces(surf.size());
697     meshFace_.setSize(surf.size());
699     label bFaceI = 0;
701     // Current region number
702     label surfRegion = regions[0];
703     label foamRegion = regionToBoundaryPatch[surfRegion];
705     Pout<< "Surface region " << surfRegion << " becomes boundary patch "
706         << foamRegion << " with name " << patches_[foamRegion].name() << endl;
709     // Index in bFaces of start of current patch
710     label startFaceI = 0;
712     forAll(indices, indexI)
713     {
714         label triI = indices[indexI];
716         const labelledTri& tri = surf.localFaces()[triI];
718         if (tri.region() != surfRegion)
719         {
720             // Change of region. We now know the size of the previous one.
721             boundaryPatch& bp = patches_[foamRegion];
723             bp.size() = bFaceI - startFaceI;
724             bp.start() = startFaceI;
726             surfRegion = tri.region();
727             foamRegion = regionToBoundaryPatch[surfRegion];
729             Pout<< "Surface region " << surfRegion << " becomes boundary patch "
730                 << foamRegion << " with name " << patches_[foamRegion].name()
731                 << endl;
733             startFaceI = bFaceI;
734         }
736         meshFace_[bFaceI] = triI;
738         bFaces[bFaceI++] = face(tri);
739     }
741     // Final region
742     boundaryPatch& bp = patches_[foamRegion];
744     bp.size() = bFaceI - startFaceI;
745     bp.start() = startFaceI;
747     //
748     // Construct single primitivePatch for all of boundary
749     //
751     clearOut();
753     // Store compact.
754     meshPtr_ = new bMesh(bFaces, surf.localPoints());
756     // Clear edge storage
757     featurePoints_.setSize(0);
758     featureEdges_.setSize(0);
760     featureToEdge_.setSize(0);
761     edgeToFeature_.setSize(meshPtr_->nEdges());
762     edgeToFeature_ = -1;
764     featureSegments_.setSize(0);
766     extraEdges_.setSize(0);
770 void Foam::boundaryMesh::writeTriSurface(const fileName& fName) const
772     geometricSurfacePatchList surfPatches(patches_.size());
774     forAll(patches_, patchI)
775     {
776         const boundaryPatch& bp = patches_[patchI];
778         surfPatches[patchI] =
779             geometricSurfacePatch
780             (
781                 bp.physicalType(),
782                 bp.name(),
783                 patchI
784             );
785     }
787     //
788     // Simple triangulation.
789     //
791     // Get number of triangles per face
792     labelList nTris(mesh().size());
794     label totalNTris = getNTris(0, mesh().size(), nTris);
796     // Determine per face the starting triangle.
797     labelList startTri(mesh().size());
799     label triI = 0;
801     forAll(mesh(), faceI)
802     {
803         startTri[faceI] = triI;
805         triI += nTris[faceI];
806     }
808     // Triangulate
809     labelList triVerts(3*totalNTris);
811     triangulate(0, mesh().size(), totalNTris, triVerts);
813     // Convert to labelledTri
815     List<labelledTri> tris(totalNTris);
817     triI = 0;
819     forAll(patches_, patchI)
820     {
821         const boundaryPatch& bp = patches_[patchI];
823         forAll(bp, patchFaceI)
824         {
825             label faceI = bp.start() + patchFaceI;
827             label triVertI = 3*startTri[faceI];
829             for (label faceTriI = 0; faceTriI < nTris[faceI]; faceTriI++)
830             {
831                 label v0 = triVerts[triVertI++];
832                 label v1 = triVerts[triVertI++];
833                 label v2 = triVerts[triVertI++];
835                 tris[triI++] = labelledTri(v0, v1, v2, patchI);
836             }
837         }
838     }
840     triSurface surf(tris, surfPatches, mesh().points());
842     OFstream surfStream(fName);
844     surf.write(surfStream);
848 // Get index in this (boundaryMesh) of face nearest to each boundary face in
849 // pMesh.
850 // Origininally all triangles/faces of boundaryMesh would be bunged into
851 // one big octree. Problem was that faces on top of each other, differing
852 // only in sign of normal, could not be found separately. It would always
853 // find only one. We could detect that it was probably finding the wrong one
854 // (based on normal) but could not 'tell' the octree to retrieve the other
855 // one (since they occupy exactly the same space)
856 // So now faces get put into different octrees depending on normal.
857 // !It still will not be possible to differentiate between two faces on top
858 // of each other having the same normal
859 Foam::labelList Foam::boundaryMesh::getNearest
861     const primitiveMesh& pMesh,
862     const vector& searchSpan
863 ) const
866     // Divide faces into two bins acc. to normal
867     // - left of splitNormal
868     // - right ,,
869     DynamicList<label> leftFaces(mesh().size()/2);
870     DynamicList<label> rightFaces(mesh().size()/2);
872     forAll(mesh(), bFaceI)
873     {
874         scalar sign = mesh().faceNormals()[bFaceI] & splitNormal_;
876         if (sign > -1E-5)
877         {
878             rightFaces.append(bFaceI);
879         }
880         if (sign < 1E-5)
881         {
882             leftFaces.append(bFaceI);
883         }
884     }
886     leftFaces.shrink();
887     rightFaces.shrink();
889     if (debug)
890     {
891         Pout<< "getNearest :"
892             << " rightBin:" << rightFaces.size()
893             << " leftBin:" << leftFaces.size()
894             << endl;
895     }
897     uindirectPrimitivePatch leftPatch
898     (
899         UIndirectList<face>(mesh(), leftFaces),
900         mesh().points()
901     );
902     uindirectPrimitivePatch rightPatch
903     (
904         UIndirectList<face>(mesh(), rightFaces),
905         mesh().points()
906     );
909     // Overall bb
910     treeBoundBox overallBb(mesh().localPoints());
912     // Extend domain slightly (also makes it 3D if was 2D)
913     // Note asymmetry to avoid having faces align with octree cubes.
914     scalar tol = 1E-6 * overallBb.avgDim();
916     point& bbMin = overallBb.min();
917     bbMin.x() -= tol;
918     bbMin.y() -= tol;
919     bbMin.z() -= tol;
921     point& bbMax = overallBb.max();
922     bbMax.x() += 2*tol;
923     bbMax.y() += 2*tol;
924     bbMax.z() += 2*tol;
926     // Create the octrees
927     indexedOctree
928     <
929         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
930     > leftTree
931     (
932         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
933         (
934             false,          // cacheBb
935             leftPatch
936         ),
937         overallBb,
938         10, // maxLevel
939         10, // leafSize
940         3.0 // duplicity
941     );
942     indexedOctree
943     <
944         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
945     > rightTree
946     (
947         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
948         (
949             false,          // cacheBb
950             rightPatch
951         ),
952         overallBb,
953         10, // maxLevel
954         10, // leafSize
955         3.0 // duplicity
956     );
958     if (debug)
959     {
960         Pout<< "getNearest : built trees" << endl;
961     }
964     const vectorField& ns = mesh().faceNormals();
967     //
968     // Search nearest triangle centre for every polyMesh boundary face
969     //
971     labelList nearestBFaceI(pMesh.nFaces() - pMesh.nInternalFaces());
973     treeBoundBox tightest;
975     const scalar searchDimSqr = magSqr(searchSpan);
977     forAll(nearestBFaceI, patchFaceI)
978     {
979         label meshFaceI = pMesh.nInternalFaces() + patchFaceI;
981         const point& ctr = pMesh.faceCentres()[meshFaceI];
983         if (debug && (patchFaceI % 1000) == 0)
984         {
985             Pout<< "getNearest : patchFace:" << patchFaceI
986                 << " meshFaceI:" << meshFaceI << " ctr:" << ctr << endl;
987         }
990         // Get normal from area vector
991         vector n = pMesh.faceAreas()[meshFaceI];
992         scalar area = mag(n);
993         n /= area;
995         scalar typDim = -GREAT;
996         const face& f = pMesh.faces()[meshFaceI];
998         forAll(f, fp)
999         {
1000             typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
1001         }
1003         // Search right tree
1004         pointIndexHit rightInfo = rightTree.findNearest(ctr, searchDimSqr);
1006         // Search left tree. Note: could start from rightDist bounding box
1007         // instead of starting from top.
1008         pointIndexHit leftInfo = leftTree.findNearest(ctr, searchDimSqr);
1010         if (rightInfo.hit())
1011         {
1012             if (leftInfo.hit())
1013             {
1014                 // Found in both trees. Compare normals.
1015                 label rightFaceI = rightFaces[rightInfo.index()];
1016                 label leftFaceI = leftFaces[leftInfo.index()];
1018                 label rightDist = mag(rightInfo.hitPoint()-ctr);
1019                 label leftDist = mag(leftInfo.hitPoint()-ctr);
1021                 scalar rightSign = n & ns[rightFaceI];
1022                 scalar leftSign = n & ns[leftFaceI];
1024                 if
1025                 (
1026                     (rightSign > 0 && leftSign > 0)
1027                  || (rightSign < 0 && leftSign < 0)
1028                 )
1029                 {
1030                     // Both same sign. Choose nearest.
1031                     if (rightDist < leftDist)
1032                     {
1033                         nearestBFaceI[patchFaceI] = rightFaceI;
1034                     }
1035                     else
1036                     {
1037                         nearestBFaceI[patchFaceI] = leftFaceI;
1038                     }
1039                 }
1040                 else
1041                 {
1042                     // Differing sign.
1043                     // - if both near enough choose one with correct sign
1044                     // - otherwise choose nearest.
1046                     // Get local dimension as max of distance between ctr and
1047                     // any face vertex.
1049                     typDim *= distanceTol_;
1051                     if (rightDist < typDim && leftDist < typDim)
1052                     {
1053                         // Different sign and nearby. Choosing matching normal
1054                         if (rightSign > 0)
1055                         {
1056                             nearestBFaceI[patchFaceI] = rightFaceI;
1057                         }
1058                         else
1059                         {
1060                             nearestBFaceI[patchFaceI] = leftFaceI;
1061                         }
1062                     }
1063                     else
1064                     {
1065                         // Different sign but faraway. Choosing nearest.
1066                         if (rightDist < leftDist)
1067                         {
1068                             nearestBFaceI[patchFaceI] = rightFaceI;
1069                         }
1070                         else
1071                         {
1072                             nearestBFaceI[patchFaceI] = leftFaceI;
1073                         }
1074                     }
1075                 }
1076             }
1077             else
1078             {
1079                 // Found in right but not in left. Choose right regardless if
1080                 // correct sign. Note: do we want this?
1081                 label rightFaceI = rightFaces[rightInfo.index()];
1082                 nearestBFaceI[patchFaceI] = rightFaceI;
1083             }
1084         }
1085         else
1086         {
1087             // No face found in right tree.
1089             if (leftInfo.hit())
1090             {
1091                 // Found in left but not in right. Choose left regardless if
1092                 // correct sign. Note: do we want this?
1093                 nearestBFaceI[patchFaceI] = leftFaces[leftInfo.index()];
1094             }
1095             else
1096             {
1097                 // No face found in left tree.
1098                 nearestBFaceI[patchFaceI] = -1;
1099             }
1100         }
1101     }
1103     return nearestBFaceI;
1107 void Foam::boundaryMesh::patchify
1109     const labelList& nearest,
1110     const polyBoundaryMesh& oldPatches,
1111     polyMesh& newMesh
1112 ) const
1115     // 2 cases to be handled:
1116     // A- patches in boundaryMesh patches_
1117     // B- patches not in boundaryMesh patches_ but in polyMesh
1119     // Create maps from patch name to new patch index.
1120     HashTable<label> nameToIndex(2*patches_.size());
1122     Map<word> indexToName(2*patches_.size());
1125     label nNewPatches = patches_.size();
1127     forAll(oldPatches, oldPatchI)
1128     {
1129         const polyPatch& patch = oldPatches[oldPatchI];
1131         label newPatchI = findPatchID(patch.name());
1133         if (newPatchI != -1)
1134         {
1135             nameToIndex.insert(patch.name(), newPatchI);
1137             indexToName.insert(newPatchI, patch.name());
1138         }
1139     }
1141     // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1142     // patches)
1143     forAll(patches_, bPatchI)
1144     {
1145         const boundaryPatch& bp = patches_[bPatchI];
1147         if (!nameToIndex.found(bp.name()))
1148         {
1149             nameToIndex.insert(bp.name(), bPatchI);
1151             indexToName.insert(bPatchI, bp.name());
1152         }
1153     }
1155     // Pass1:
1156     // Copy names&type of patches (with zero size) from old mesh as far as
1157     // possible. First patch created gets all boundary faces; all others get
1158     // zero faces (repatched later on). Exception is coupled patches which
1159     // keep their size.
1161     List<polyPatch*> newPatchPtrList(nNewPatches);
1163     label meshFaceI = newMesh.nInternalFaces();
1165     // First patch gets all non-coupled faces
1166     label facesToBeDone = newMesh.nFaces() - newMesh.nInternalFaces();
1168     forAll(patches_, bPatchI)
1169     {
1170         const boundaryPatch& bp = patches_[bPatchI];
1172         label newPatchI = nameToIndex[bp.name()];
1174         // Find corresponding patch in polyMesh
1175         label oldPatchI = findPatchID(oldPatches, bp.name());
1177         if (oldPatchI == -1)
1178         {
1179             // Newly created patch. Gets all or zero faces.
1180             if (debug)
1181             {
1182                 Pout<< "patchify : Creating new polyPatch:" << bp.name()
1183                     << " type:" << bp.physicalType() << endl;
1184             }
1186             newPatchPtrList[newPatchI] = polyPatch::New
1187             (
1188                 bp.physicalType(),
1189                 bp.name(),
1190                 facesToBeDone,
1191                 meshFaceI,
1192                 newPatchI,
1193                 newMesh.boundaryMesh()
1194             ).ptr();
1196             meshFaceI += facesToBeDone;
1198             // first patch gets all boundary faces; all others get 0.
1199             facesToBeDone = 0;
1200         }
1201         else
1202         {
1203             // Existing patch. Gets all or zero faces.
1204             const polyPatch& oldPatch = oldPatches[oldPatchI];
1206             if (debug)
1207             {
1208                 Pout<< "patchify : Cloning existing polyPatch:"
1209                     << oldPatch.name() << endl;
1210             }
1212             newPatchPtrList[newPatchI] = oldPatch.clone
1213             (
1214                 newMesh.boundaryMesh(),
1215                 newPatchI,
1216                 facesToBeDone,
1217                 meshFaceI
1218             ).ptr();
1220             meshFaceI += facesToBeDone;
1222             // first patch gets all boundary faces; all others get 0.
1223             facesToBeDone = 0;
1224         }
1225     }
1228     if (debug)
1229     {
1230         Pout<< "Patchify : new polyPatch list:" << endl;
1232         forAll(newPatchPtrList, patchI)
1233         {
1234             const polyPatch& newPatch = *newPatchPtrList[patchI];
1236             if (debug)
1237             {
1238                 Pout<< "polyPatch:" << newPatch.name() << endl
1239                     << "    type :" << newPatch.typeName << endl
1240                     << "    size :" << newPatch.size() << endl
1241                     << "    start:" << newPatch.start() << endl
1242                     << "    index:" << patchI << endl;
1243             }
1244         }
1245     }
1247     // Actually add new list of patches
1248     repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1249     polyMeshRepatcher.changePatches(newPatchPtrList);
1252     // Pass2:
1253     // Change patch type for face
1255     if (newPatchPtrList.size())
1256     {
1257         List<DynamicList<label> > patchFaces(nNewPatches);
1259         // Give reasonable estimate for size of patches
1260         label nAvgFaces =
1261             (newMesh.nFaces() - newMesh.nInternalFaces())
1262           / nNewPatches;
1264         forAll(patchFaces, newPatchI)
1265         {
1266             patchFaces[newPatchI].setCapacity(nAvgFaces);
1267         }
1269         //
1270         // Sort faces acc. to new patch index. Can loop over all old patches
1271         // since will contain all faces.
1272         //
1274         forAll(oldPatches, oldPatchI)
1275         {
1276             const polyPatch& patch = oldPatches[oldPatchI];
1278             forAll(patch, patchFaceI)
1279             {
1280                 // Put face into region given by nearest boundary face
1282                 label meshFaceI = patch.start() + patchFaceI;
1284                 label bFaceI = meshFaceI - newMesh.nInternalFaces();
1286                 patchFaces[whichPatch(nearest[bFaceI])].append(meshFaceI);
1287             }
1288         }
1290         forAll(patchFaces, newPatchI)
1291         {
1292             patchFaces[newPatchI].shrink();
1293         }
1296         // Change patch > 0. (since above we put all faces into the zeroth
1297         // patch)
1299         for (label newPatchI = 1; newPatchI < patchFaces.size(); newPatchI++)
1300         {
1301             const labelList& pFaces = patchFaces[newPatchI];
1303             forAll(pFaces, pFaceI)
1304             {
1305                 polyMeshRepatcher.changePatchID(pFaces[pFaceI], newPatchI);
1306             }
1307         }
1309         polyMeshRepatcher.repatch();
1310     }
1314 void Foam::boundaryMesh::setFeatureEdges(const scalar minCos)
1316     edgeToFeature_.setSize(mesh().nEdges());
1318     edgeToFeature_ = -1;
1320     // 1. Mark feature edges
1322     // Storage for edge labels that are features. Trim later.
1323     featureToEdge_.setSize(mesh().nEdges());
1325     label featureI = 0;
1327     if (minCos >= 0.9999)
1328     {
1329         // Select everything
1330         forAll(mesh().edges(), edgeI)
1331         {
1332             edgeToFeature_[edgeI] = featureI;
1333             featureToEdge_[featureI++] = edgeI;
1334         }
1335     }
1336     else
1337     {
1338         forAll(mesh().edges(), edgeI)
1339         {
1340             const labelList& eFaces = mesh().edgeFaces()[edgeI];
1342             if (eFaces.size() == 2)
1343             {
1344                 label face0I = eFaces[0];
1346                 label face1I = eFaces[1];
1348                 ////- Uncomment below code if you want to include patch
1349                 ////  boundaries in feature edges.
1350                 //if (whichPatch(face0I) != whichPatch(face1I))
1351                 //{
1352                 //    edgeToFeature_[edgeI] = featureI;
1353                 //    featureToEdge_[featureI++] = edgeI;
1354                 //}
1355                 //else
1356                 {
1357                     const vector& n0 = mesh().faceNormals()[face0I];
1359                     const vector& n1 = mesh().faceNormals()[face1I];
1361                     float cosAng = n0 & n1;
1363                     if (cosAng < minCos)
1364                     {
1365                         edgeToFeature_[edgeI] = featureI;
1366                         featureToEdge_[featureI++] = edgeI;
1367                     }
1368                 }
1369             }
1370             else
1371             {
1372                 //Should not occur: 0 or more than two faces
1373                 edgeToFeature_[edgeI] = featureI;
1374                 featureToEdge_[featureI++] = edgeI;
1375             }
1376         }
1377     }
1379     // Trim featureToEdge_ to actual number of edges.
1380     featureToEdge_.setSize(featureI);
1382     //
1383     // Compact edges i.e. relabel vertices.
1384     //
1386     featureEdges_.setSize(featureI);
1387     featurePoints_.setSize(mesh().nPoints());
1389     labelList featToMeshPoint(mesh().nPoints(), -1);
1391     label featPtI = 0;
1393     forAll(featureToEdge_, fEdgeI)
1394     {
1395         label edgeI = featureToEdge_[fEdgeI];
1397         const edge& e = mesh().edges()[edgeI];
1399         label start = featToMeshPoint[e.start()];
1401         if (start == -1)
1402         {
1403             featToMeshPoint[e.start()] = featPtI;
1405             featurePoints_[featPtI] = mesh().points()[e.start()];
1407             start = featPtI;
1409             featPtI++;
1410         }
1412         label end = featToMeshPoint[e.end()];
1414         if (end == -1)
1415         {
1416             featToMeshPoint[e.end()] = featPtI;
1418             featurePoints_[featPtI] = mesh().points()[e.end()];
1420             end = featPtI;
1422             featPtI++;
1423         }
1425         // Store with renumbered vertices.
1426         featureEdges_[fEdgeI] = edge(start, end);
1427     }
1429     // Compact points
1430     featurePoints_.setSize(featPtI);
1433     //
1434     // 2. Mark endpoints of feature segments. These are points with
1435     // != 2 feature edges connected.
1436     // Note: can add geometric constraint here as well that if 2 feature
1437     // edges the angle between them should be less than xxx.
1438     //
1440     boolList isFeaturePoint(mesh().nPoints(), false);
1442     forAll(featureToEdge_, featI)
1443     {
1444         label edgeI = featureToEdge_[featI];
1446         const edge& e = mesh().edges()[edgeI];
1448         if (nFeatureEdges(e.start()) != 2)
1449         {
1450             isFeaturePoint[e.start()] = true;
1451         }
1453         if (nFeatureEdges(e.end()) != 2)
1454         {
1455             isFeaturePoint[e.end()] = true;
1456         }
1457     }
1460     //
1461     // 3: Split feature edges into segments:
1462     // find point with not 2 feature edges -> start of feature segment
1463     //
1465     DynamicList<labelList> segments;
1468     boolList featVisited(featureToEdge_.size(), false);
1470     do
1471     {
1472         label startFeatI = -1;
1474         forAll(featVisited, featI)
1475         {
1476             if (!featVisited[featI])
1477             {
1478                 startFeatI = featI;
1480                 break;
1481             }
1482         }
1484         if (startFeatI == -1)
1485         {
1486             // No feature lines left.
1487             break;
1488         }
1490         segments.append
1491         (
1492             collectSegment
1493             (
1494                 isFeaturePoint,
1495                 featureToEdge_[startFeatI],
1496                 featVisited
1497             )
1498         );
1499     }
1500     while (true);
1503     //
1504     // Store in *this
1505     //
1506     featureSegments_.setSize(segments.size());
1508     forAll(featureSegments_, segmentI)
1509     {
1510         featureSegments_[segmentI] = segments[segmentI];
1511     }
1515 void Foam::boundaryMesh::setExtraEdges(const label edgeI)
1517     labelList minDistance(mesh().nEdges(), -1);
1519     // All edge labels encountered
1520     DynamicList<label> visitedEdges;
1522     // Floodfill from edgeI starting from distance 0. Stop at distance.
1523     markEdges(8, edgeI, 0, minDistance, visitedEdges);
1525     // Set edge labels to display
1526     extraEdges_.transfer(visitedEdges);
1530 Foam::label Foam::boundaryMesh::whichPatch(const label faceI) const
1532     forAll(patches_, patchI)
1533     {
1534         const boundaryPatch& bp = patches_[patchI];
1536         if ((faceI >= bp.start()) && (faceI < (bp.start() + bp.size())))
1537         {
1538             return patchI;
1539         }
1540     }
1542     FatalErrorIn("boundaryMesh::whichPatch(const label)")
1543         << "Cannot find face " << faceI << " in list of boundaryPatches "
1544         << patches_
1545         << abort(FatalError);
1547     return -1;
1551 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1553     forAll(patches_, patchI)
1554     {
1555         if (patches_[patchI].name() == patchName)
1556         {
1557             return patchI;
1558         }
1559     }
1561     return -1;
1565 void Foam::boundaryMesh::addPatch(const word& patchName)
1567     patches_.setSize(patches_.size() + 1);
1569     // Add empty patch at end of patch list.
1571     label patchI = patches_.size()-1;
1573     boundaryPatch* bpPtr = new boundaryPatch
1574     (
1575         patchName,
1576         patchI,
1577         0,
1578         mesh().size(),
1579         "empty"
1580     );
1582     patches_.set(patchI, bpPtr);
1584     if (debug)
1585     {
1586         Pout<< "addPatch : patches now:" << endl;
1588         forAll(patches_, patchI)
1589         {
1590             const boundaryPatch& bp = patches_[patchI];
1592             Pout<< "    name  : " << bp.name() << endl
1593                 << "    size  : " << bp.size() << endl
1594                 << "    start : " << bp.start() << endl
1595                 << "    type  : " << bp.physicalType() << endl
1596                 << endl;
1597         }
1598     }
1602 void Foam::boundaryMesh::deletePatch(const word& patchName)
1604     label delPatchI = findPatchID(patchName);
1606     if (delPatchI == -1)
1607     {
1608         FatalErrorIn("boundaryMesh::deletePatch(const word&")
1609             << "Can't find patch named " << patchName
1610             << abort(FatalError);
1611     }
1613     if (patches_[delPatchI].size())
1614     {
1615         FatalErrorIn("boundaryMesh::deletePatch(const word&")
1616             << "Trying to delete non-empty patch " << patchName
1617             << endl << "Current size:" << patches_[delPatchI].size()
1618             << abort(FatalError);
1619     }
1621     PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1623     for (label patchI = 0; patchI < delPatchI; patchI++)
1624     {
1625         newPatches.set(patchI, patches_[patchI].clone());
1626     }
1628     // Move patches down, starting from delPatchI.
1630     for (label patchI = delPatchI + 1; patchI < patches_.size(); patchI++)
1631     {
1632         newPatches.set(patchI - 1, patches_[patchI].clone());
1633     }
1635     patches_.clear();
1637     patches_ = newPatches;
1639     if (debug)
1640     {
1641         Pout<< "deletePatch : patches now:" << endl;
1643         forAll(patches_, patchI)
1644         {
1645             const boundaryPatch& bp = patches_[patchI];
1647             Pout<< "    name  : " << bp.name() << endl
1648                 << "    size  : " << bp.size() << endl
1649                 << "    start : " << bp.start() << endl
1650                 << "    type  : " << bp.physicalType() << endl
1651                 << endl;
1652         }
1653     }
1657 void Foam::boundaryMesh::changePatchType
1659     const word& patchName,
1660     const word& patchType
1663     label changeI = findPatchID(patchName);
1665     if (changeI == -1)
1666     {
1667         FatalErrorIn("boundaryMesh::changePatchType(const word&, const word&)")
1668             << "Can't find patch named " << patchName
1669             << abort(FatalError);
1670     }
1673     // Cause we can't reassign to individual PtrList elems ;-(
1674     // work on copy
1677     PtrList<boundaryPatch> newPatches(patches_.size());
1679     forAll(patches_, patchI)
1680     {
1681         if (patchI == changeI)
1682         {
1683             // Create copy but for type
1684             const boundaryPatch& oldBp = patches_[patchI];
1686             boundaryPatch* bpPtr = new boundaryPatch
1687             (
1688                 oldBp.name(),
1689                 oldBp.index(),
1690                 oldBp.size(),
1691                 oldBp.start(),
1692                 patchType
1693             );
1695             newPatches.set(patchI, bpPtr);
1696         }
1697         else
1698         {
1699             // Create copy
1700             newPatches.set(patchI, patches_[patchI].clone());
1701         }
1702     }
1704     patches_ = newPatches;
1708 void Foam::boundaryMesh::changeFaces
1710     const labelList& patchIDs,
1711     labelList& oldToNew
1714     if (patchIDs.size() != mesh().size())
1715     {
1716         FatalErrorIn("boundaryMesh::changeFaces(const labelList& patchIDs)")
1717             << "List of patchIDs not equal to number of faces." << endl
1718             << "PatchIDs size:" << patchIDs.size()
1719             << " nFaces::" << mesh().size()
1720             << abort(FatalError);
1721     }
1723     // Count number of faces for each patch
1725     labelList nFaces(patches_.size(), 0);
1727     forAll(patchIDs, faceI)
1728     {
1729         label patchID = patchIDs[faceI];
1731         if (patchID < 0 || patchID >= patches_.size())
1732         {
1733             FatalErrorIn("boundaryMesh::changeFaces(const labelList&)")
1734                 << "PatchID " << patchID << " out of range"
1735                 << abort(FatalError);
1736         }
1737         nFaces[patchID]++;
1738     }
1741     // Determine position in faces_ for each patch
1743     labelList startFace(patches_.size());
1745     startFace[0] = 0;
1747     for (label patchI = 1; patchI < patches_.size(); patchI++)
1748     {
1749         startFace[patchI] = startFace[patchI-1] + nFaces[patchI-1];
1750     }
1752     // Update patch info
1753     PtrList<boundaryPatch> newPatches(patches_.size());
1755     forAll(patches_, patchI)
1756     {
1757         const boundaryPatch& bp = patches_[patchI];
1759         newPatches.set
1760         (
1761             patchI,
1762             new boundaryPatch
1763             (
1764                 bp.name(),
1765                 patchI,
1766                 nFaces[patchI],
1767                 startFace[patchI],
1768                 bp.physicalType()
1769             )
1770         );
1771     }
1772     patches_ = newPatches;
1774     if (debug)
1775     {
1776         Pout<< "changeFaces : patches now:" << endl;
1778         forAll(patches_, patchI)
1779         {
1780             const boundaryPatch& bp = patches_[patchI];
1782             Pout<< "    name  : " << bp.name() << endl
1783                 << "    size  : " << bp.size() << endl
1784                 << "    start : " << bp.start() << endl
1785                 << "    type  : " << bp.physicalType() << endl
1786                 << endl;
1787         }
1788     }
1791     // Construct face mapping array
1792     oldToNew.setSize(patchIDs.size());
1794     forAll(patchIDs, faceI)
1795     {
1796         int patchID = patchIDs[faceI];
1798         oldToNew[faceI] = startFace[patchID]++;
1799     }
1801     // Copy faces into correct position and maintain label of original face
1802     faceList newFaces(mesh().size());
1804     labelList newMeshFace(mesh().size());
1806     forAll(oldToNew, faceI)
1807     {
1808         newFaces[oldToNew[faceI]] = mesh()[faceI];
1809         newMeshFace[oldToNew[faceI]] = meshFace_[faceI];
1810     }
1812     // Reconstruct 'mesh' from new faces and (copy of) existing points.
1813     bMesh* newMeshPtr_ = new bMesh(newFaces, mesh().points());
1815     // Reset meshFace_ to new ordering.
1816     meshFace_.transfer(newMeshFace);
1819     // Remove old PrimitivePatch on meshPtr_.
1820     clearOut();
1822     // And insert new 'mesh'.
1823     meshPtr_ = newMeshPtr_;
1827 Foam::label Foam::boundaryMesh::getNTris(const label faceI) const
1829     const face& f = mesh()[faceI];
1831     return f.nTriangles(mesh().points());
1835 Foam::label Foam::boundaryMesh::getNTris
1837     const label startFaceI,
1838     const label nFaces,
1839     labelList& nTris
1840 ) const
1842     label totalNTris = 0;
1844     nTris.setSize(nFaces);
1846     for (label i = 0; i < nFaces; i++)
1847     {
1848         label faceNTris = getNTris(startFaceI + i);
1850         nTris[i] = faceNTris;
1852         totalNTris += faceNTris;
1853     }
1854     return totalNTris;
1858 // Simple triangulation of face subset. Stores vertices in tris[] as three
1859 // consecutive vertices per triangle.
1860 void Foam::boundaryMesh::triangulate
1862     const label startFaceI,
1863     const label nFaces,
1864     const label totalNTris,
1865     labelList& triVerts
1866 ) const
1868     // Triangulate faces.
1869     triVerts.setSize(3*totalNTris);
1871     label vertI = 0;
1873     for (label i = 0; i < nFaces; i++)
1874     {
1875         label faceI = startFaceI + i;
1877         const face& f = mesh()[faceI];
1879         // Have face triangulate itself (results in faceList)
1880         faceList triFaces(f.nTriangles(mesh().points()));
1882         label nTri = 0;
1884         f.triangles(mesh().points(), nTri, triFaces);
1886         // Copy into triVerts
1888         forAll(triFaces, triFaceI)
1889         {
1890             const face& triF = triFaces[triFaceI];
1892             triVerts[vertI++] = triF[0];
1893             triVerts[vertI++] = triF[1];
1894             triVerts[vertI++] = triF[2];
1895         }
1896     }
1900 // Number of local points in subset.
1901 Foam::label Foam::boundaryMesh::getNPoints
1903     const label startFaceI,
1904     const label nFaces
1905 ) const
1907     SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1909     primitivePatch patch(patchFaces, mesh().points());
1911     return patch.nPoints();
1915 // Triangulation of face subset in local coords.
1916 void Foam::boundaryMesh::triangulateLocal
1918     const label startFaceI,
1919     const label nFaces,
1920     const label totalNTris,
1921     labelList& triVerts,
1922     labelList& localToGlobal
1923 ) const
1925     SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1927     primitivePatch patch(patchFaces, mesh().points());
1929     // Map from local to mesh().points() addressing
1930     localToGlobal = patch.meshPoints();
1932     // Triangulate patch faces.
1933     triVerts.setSize(3*totalNTris);
1935     label vertI = 0;
1937     for (label i = 0; i < nFaces; i++)
1938     {
1939         // Local face
1940         const face& f = patch.localFaces()[i];
1942         // Have face triangulate itself (results in faceList)
1943         faceList triFaces(f.nTriangles(patch.localPoints()));
1945         label nTri = 0;
1947         f.triangles(patch.localPoints(), nTri, triFaces);
1949         // Copy into triVerts
1951         forAll(triFaces, triFaceI)
1952         {
1953             const face& triF = triFaces[triFaceI];
1955             triVerts[vertI++] = triF[0];
1956             triVerts[vertI++] = triF[1];
1957             triVerts[vertI++] = triF[2];
1958         }
1959     }
1963 void Foam::boundaryMesh::markFaces
1965     const labelList& protectedEdges,
1966     const label seedFaceI,
1967     boolList& visited
1968 ) const
1970     boolList protectedEdge(mesh().nEdges(), false);
1972     forAll(protectedEdges, i)
1973     {
1974         protectedEdge[protectedEdges[i]] = true;
1975     }
1978     // Initialize zone for all faces to -1
1979     labelList currentZone(mesh().size(), -1);
1981     // Mark with 0 all faces reachable from seedFaceI
1982     markZone(protectedEdge, seedFaceI, 0, currentZone);
1984     // Set in visited all reached ones.
1985     visited.setSize(mesh().size());
1987     forAll(currentZone, faceI)
1988     {
1989         if (currentZone[faceI] == 0)
1990         {
1991             visited[faceI] = true;
1992         }
1993         else
1994         {
1995             visited[faceI] = false;
1996         }
1997     }
2001 // ************************************************************************* //