Merge branch 'master' of ssh://git.code.sf.net/p/foam-extend/foam-extend-3.2
[foam-extend-3.2.git] / applications / utilities / surface / surfaceToPatch / boundaryMesh.C
blobf517282648901597852df38397201968700e0cd2
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend 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 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "boundaryMesh.H"
27 #include "objectRegistry.H"
28 #include "foamTime.H"
29 #include "polyMesh.H"
30 #include "repatchPolyTopoChanger.H"
31 #include "faceList.H"
32 #include "indexedOctree.H"
33 #include "treeDataPrimitivePatch.H"
34 #include "triSurface.H"
35 #include "SortableList.H"
36 #include "OFstream.H"
37 #include "uindirectPrimitivePatch.H"
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(Foam::boundaryMesh, 0);
43 // Normal along which to divide faces into categories (used in getNearest)
44 const Foam::vector Foam::boundaryMesh::splitNormal_(3, 2, 1);
46 // Distance to face tolerance for getNearest
47 const Foam::scalar Foam::boundaryMesh::distanceTol_ = 1E-2;
50 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
52 // Returns number of feature edges connected to pointI
53 Foam::label Foam::boundaryMesh::nFeatureEdges(label pointI) const
55     label nFeats = 0;
57     const labelList& pEdges = mesh().pointEdges()[pointI];
59     forAll(pEdges, pEdgeI)
60     {
61         label edgeI = pEdges[pEdgeI];
63         if (edgeToFeature_[edgeI] != -1)
64         {
65             nFeats++;
66         }
67     }
68     return nFeats;
72 // Returns next feature edge connected to pointI
73 Foam::label Foam::boundaryMesh::nextFeatureEdge
75     const label edgeI,
76     const label vertI
77 ) const
79     const labelList& pEdges = mesh().pointEdges()[vertI];
81     forAll(pEdges, pEdgeI)
82     {
83         label nbrEdgeI = pEdges[pEdgeI];
85         if (nbrEdgeI != edgeI)
86         {
87             label featI = edgeToFeature_[nbrEdgeI];
89             if (featI != -1)
90             {
91                 return nbrEdgeI;
92             }
93         }
94     }
96     return -1;
100 // Finds connected feature edges, starting from startPointI and returns
101 // feature labels (not edge labels). Marks feature edges handled in
102 // featVisited.
103 Foam::labelList Foam::boundaryMesh::collectSegment
105     const boolList& isFeaturePoint,
106     const label startEdgeI,
107     boolList& featVisited
108 ) const
110     // Find starting feature point on edge.
112     label edgeI = startEdgeI;
114     const edge& e = mesh().edges()[edgeI];
116     label vertI = e.start();
118     while (!isFeaturePoint[vertI])
119     {
120         // Step to next feature edge
122         edgeI = nextFeatureEdge(edgeI, vertI);
124         if ((edgeI == -1) || (edgeI == startEdgeI))
125         {
126             break;
127         }
129         // Step to next vertex on edge
131         const edge& e = mesh().edges()[edgeI];
133         vertI = e.otherVertex(vertI);
134     }
136     //
137     // Now we have:
138     //    edgeI : first edge on this segment
139     //    vertI : one of the endpoints of this segment
140     //
141     // Start walking other way and storing edges as we go along.
142     //
144     // Untrimmed storage for current segment
145     labelList featLabels(featureEdges_.size());
147     label featLabelI = 0;
149     label initEdgeI = edgeI;
151     do
152     {
153         // Mark edge as visited
154         label featI = edgeToFeature_[edgeI];
156         if (featI == -1)
157         {
158             FatalErrorIn("boundaryMesh::collectSegment")
159                 << "Problem" << abort(FatalError);
160         }
161         featLabels[featLabelI++] = featI;
163         featVisited[featI] = true;
165         // Step to next vertex on edge
167         const edge& e = mesh().edges()[edgeI];
169         vertI = e.otherVertex(vertI);
171         // Step to next feature edge
173         edgeI = nextFeatureEdge(edgeI, vertI);
175         if ((edgeI == -1) || (edgeI == initEdgeI))
176         {
177             break;
178         }
179     }
180     while (!isFeaturePoint[vertI]);
183     // Trim to size
184     featLabels.setSize(featLabelI);
186     return featLabels;
190 void Foam::boundaryMesh::markEdges
192     const label maxDistance,
193     const label edgeI,
194     const label distance,
195     labelList& minDistance,
196     DynamicList<label>& visited
197 ) const
199     if (distance < maxDistance)
200     {
201         // Don't do anything if reached beyond maxDistance.
203         if (minDistance[edgeI] == -1)
204         {
205             // First visit of edge. Store edge label.
206             visited.append(edgeI);
207         }
208         else if (minDistance[edgeI] <= distance)
209         {
210             // Already done this edge
211             return;
212         }
214         minDistance[edgeI] = distance;
216         const edge& e = mesh().edges()[edgeI];
218         // Do edges connected to e.start
219         const labelList& startEdges = mesh().pointEdges()[e.start()];
221         forAll(startEdges, pEdgeI)
222         {
223             markEdges
224             (
225                 maxDistance,
226                 startEdges[pEdgeI],
227                 distance+1,
228                 minDistance,
229                 visited
230             );
231         }
233         // Do edges connected to e.end
234         const labelList& endEdges = mesh().pointEdges()[e.end()];
236         forAll(endEdges, pEdgeI)
237         {
238             markEdges
239             (
240                 maxDistance,
241                 endEdges[pEdgeI],
242                 distance+1,
243                 minDistance,
244                 visited
245             );
246         }
247     }
251 Foam::label Foam::boundaryMesh::findPatchID
253     const polyPatchList& patches,
254     const word& patchName
255 ) const
257     forAll(patches, patchI)
258     {
259         if (patches[patchI].name() == patchName)
260         {
261             return patchI;
262         }
263     }
265     return -1;
269 Foam::wordList Foam::boundaryMesh::patchNames() const
271     wordList names(patches_.size());
273     forAll(patches_, patchI)
274     {
275         names[patchI] = patches_[patchI].name();
276     }
277     return names;
281 Foam::label Foam::boundaryMesh::whichPatch
283     const polyPatchList& patches,
284     const label faceI
285 ) const
287     forAll(patches, patchI)
288     {
289         const polyPatch& pp = patches[patchI];
291         if ((faceI >= pp.start()) && (faceI < (pp.start() + pp.size())))
292         {
293             return patchI;
294         }
295     }
296     return -1;
300 // Gets labels of changed faces and propagates them to the edges. Returns
301 // labels of edges changed.
302 Foam::labelList Foam::boundaryMesh::faceToEdge
304     const boolList& regionEdge,
305     const label region,
306     const labelList& changedFaces,
307     labelList& edgeRegion
308 ) const
310     labelList changedEdges(mesh().nEdges(), -1);
311     label changedI = 0;
313     forAll(changedFaces, i)
314     {
315         label faceI = changedFaces[i];
317         const labelList& fEdges = mesh().faceEdges()[faceI];
319         forAll(fEdges, fEdgeI)
320         {
321             label edgeI = fEdges[fEdgeI];
323             if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
324             {
325                 edgeRegion[edgeI] = region;
327                 changedEdges[changedI++] = edgeI;
328             }
329         }
330     }
332     changedEdges.setSize(changedI);
334     return changedEdges;
338 // Reverse of faceToEdge: gets edges and returns faces
339 Foam::labelList Foam::boundaryMesh::edgeToFace
341     const label region,
342     const labelList& changedEdges,
343     labelList& faceRegion
344 ) const
346     labelList changedFaces(mesh().size(), -1);
347     label changedI = 0;
349     forAll(changedEdges, i)
350     {
351         label edgeI = changedEdges[i];
353         const labelList& eFaces = mesh().edgeFaces()[edgeI];
355         forAll(eFaces, eFaceI)
356         {
357             label faceI = eFaces[eFaceI];
359             if (faceRegion[faceI] == -1)
360             {
361                 faceRegion[faceI] = region;
363                 changedFaces[changedI++] = faceI;
364             }
365         }
366     }
368     changedFaces.setSize(changedI);
370     return changedFaces;
374 // Finds area, starting at faceI, delimited by borderEdge
375 void Foam::boundaryMesh::markZone
377     const boolList& borderEdge,
378     label faceI,
379     label currentZone,
380     labelList& faceZone
381 ) const
383     faceZone[faceI] = currentZone;
385     // List of faces whose faceZone has been set.
386     labelList changedFaces(1, faceI);
387     // List of edges whose faceZone has been set.
388     labelList changedEdges;
390     // Zones on all edges.
391     labelList edgeZone(mesh().nEdges(), -1);
393     while(1)
394     {
395         changedEdges = faceToEdge
396         (
397             borderEdge,
398             currentZone,
399             changedFaces,
400             edgeZone
401         );
403         if (debug)
404         {
405             Pout<< "From changedFaces:" << changedFaces.size()
406                 << " to changedEdges:" << changedEdges.size()
407                 << endl;
408         }
410         if (changedEdges.empty())
411         {
412             break;
413         }
415         changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
417         if (debug)
418         {
419             Pout<< "From changedEdges:" << changedEdges.size()
420                 << " to changedFaces:" << changedFaces.size()
421                 << endl;
422         }
424         if (changedFaces.empty())
425         {
426             break;
427         }
428     }
432 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
434 // Null constructor
435 Foam::boundaryMesh::boundaryMesh()
437     meshPtr_(NULL),
438     patches_(),
439     meshFace_(),
440     featurePoints_(),
441     featureEdges_(),
442     featureToEdge_(),
443     edgeToFeature_(),
444     featureSegments_(),
445     extraEdges_()
449 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
451 Foam::boundaryMesh::~boundaryMesh()
453     clearOut();
457 void Foam::boundaryMesh::clearOut()
459     if (meshPtr_)
460     {
461         delete meshPtr_;
463         meshPtr_ = NULL;
464     }
468 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
470 void Foam::boundaryMesh::read(const polyMesh& mesh)
472     patches_.clear();
474     patches_.setSize(mesh.boundaryMesh().size());
476     // Number of boundary faces
477     label nBFaces = mesh.nFaces() - mesh.nInternalFaces();
479     faceList bFaces(nBFaces);
481     meshFace_.setSize(nBFaces);
483     label bFaceI = 0;
485     // Collect all boundary faces.
486     forAll(mesh.boundaryMesh(), patchI)
487     {
488         const polyPatch& pp = mesh.boundaryMesh()[patchI];
490         patches_.set
491         (
492             patchI,
493             new boundaryPatch
494             (
495                 pp.name(),
496                 patchI,
497                 pp.size(),
498                 bFaceI,
499                 pp.type()
500             )
501         );
503         // Collect all faces in global numbering.
504         forAll(pp, patchFaceI)
505         {
506             meshFace_[bFaceI] = pp.start() + patchFaceI;
508             bFaces[bFaceI] = pp[patchFaceI];
510             bFaceI++;
511         }
512     }
515     if (debug)
516     {
517         Pout<< "read : patches now:" << endl;
519         forAll(patches_, patchI)
520         {
521             const boundaryPatch& bp = patches_[patchI];
523             Pout<< "    name  : " << bp.name() << endl
524                 << "    size  : " << bp.size() << endl
525                 << "    start : " << bp.start() << endl
526                 << "    type  : " << bp.physicalType() << endl
527                 << endl;
528         }
529     }
531     //
532     // Construct single patch for all of boundary
533     //
535     // Temporary primitivePatch to calculate compact points & faces.
536     PrimitivePatch<face, List, const pointField&> globalPatch
537     (
538         bFaces,
539         mesh.points()
540     );
542     // Store in local(compact) addressing
543     clearOut();
545     meshPtr_ = new bMesh(globalPatch.localFaces(), globalPatch.localPoints());
548     if (debug & 2)
549     {
550         const bMesh& msh = *meshPtr_;
552         Pout<< "** Start of Faces **" << endl;
554         forAll(msh, faceI)
555         {
556             const face& f = msh[faceI];
558             point ctr(vector::zero);
560             forAll(f, fp)
561             {
562                 ctr += msh.points()[f[fp]];
563             }
564             ctr /= f.size();
566             Pout<< "    " << faceI
567                 << " ctr:" << ctr
568                 << " verts:" << f
569                 << endl;
570         }
572         Pout<< "** End of Faces **" << endl;
574         Pout<< "** Start of Points **" << endl;
576         forAll(msh.points(), pointI)
577         {
578             Pout<< "    " << pointI
579                 << " coord:" << msh.points()[pointI]
580                 << endl;
581         }
583         Pout<< "** End of Points **" << endl;
584     }
586     // Clear edge storage
587     featurePoints_.setSize(0);
588     featureEdges_.setSize(0);
590     featureToEdge_.setSize(0);
591     edgeToFeature_.setSize(meshPtr_->nEdges());
592     edgeToFeature_ = -1;
594     featureSegments_.setSize(0);
596     extraEdges_.setSize(0);
600 void Foam::boundaryMesh::readTriSurface(const fileName& fName)
602     triSurface surf(fName);
604     if (surf.empty())
605     {
606         return;
607     }
609     // Sort according to region
610     SortableList<label> regions(surf.size());
612     forAll(surf, triI)
613     {
614         regions[triI] = surf[triI].region();
615     }
616     regions.sort();
618     // Determine region mapping.
619     Map<label> regionToBoundaryPatch;
621     label oldRegion = -1111;
622     label boundPatch = 0;
624     forAll(regions, i)
625     {
626         if (regions[i] != oldRegion)
627         {
628             regionToBoundaryPatch.insert(regions[i], boundPatch);
630             oldRegion = regions[i];
631             boundPatch++;
632         }
633     }
635     const geometricSurfacePatchList& surfPatches = surf.patches();
637     patches_.clear();
639     if (surfPatches.size() == regionToBoundaryPatch.size())
640     {
641         // There are as many surface patches as region numbers in triangles
642         // so use the surface patches
644         patches_.setSize(surfPatches.size());
646         // Take over patches, setting size to 0 for now.
647         forAll(surfPatches, patchI)
648         {
649             const geometricSurfacePatch& surfPatch = surfPatches[patchI];
651             patches_.set
652             (
653                 patchI,
654                 new boundaryPatch
655                 (
656                     surfPatch.name(),
657                     patchI,
658                     0,
659                     0,
660                     surfPatch.geometricType()
661                 )
662             );
663         }
664     }
665     else
666     {
667         // There are not enough surface patches. Make up my own.
669         patches_.setSize(regionToBoundaryPatch.size());
671         forAll(patches_, patchI)
672         {
673             patches_.set
674             (
675                 patchI,
676                 new boundaryPatch
677                 (
678                     "patch" + name(patchI),
679                     patchI,
680                     0,
681                     0,
682                     "empty"
683                 )
684             );
685         }
686     }
688     //
689     // Copy according into bFaces according to regions
690     //
692     const labelList& indices = regions.indices();
694     faceList bFaces(surf.size());
696     meshFace_.setSize(surf.size());
698     label bFaceI = 0;
700     // Current region number
701     label surfRegion = regions[0];
702     label foamRegion = regionToBoundaryPatch[surfRegion];
704     Pout<< "Surface region " << surfRegion << " becomes boundary patch "
705         << foamRegion << " with name " << patches_[foamRegion].name() << endl;
708     // Index in bFaces of start of current patch
709     label startFaceI = 0;
711     forAll(indices, indexI)
712     {
713         label triI = indices[indexI];
715         const labelledTri& tri = surf.localFaces()[triI];
717         if (tri.region() != surfRegion)
718         {
719             // Change of region. We now know the size of the previous one.
720             boundaryPatch& bp = patches_[foamRegion];
722             bp.size() = bFaceI - startFaceI;
723             bp.start() = startFaceI;
725             surfRegion = tri.region();
726             foamRegion = regionToBoundaryPatch[surfRegion];
728             Pout<< "Surface region " << surfRegion << " becomes boundary patch "
729                 << foamRegion << " with name " << patches_[foamRegion].name()
730                 << endl;
732             startFaceI = bFaceI;
733         }
735         meshFace_[bFaceI] = triI;
737         bFaces[bFaceI++] = face(tri);
738     }
740     // Final region
741     boundaryPatch& bp = patches_[foamRegion];
743     bp.size() = bFaceI - startFaceI;
744     bp.start() = startFaceI;
746     //
747     // Construct single primitivePatch for all of boundary
748     //
750     clearOut();
752     // Store compact.
753     meshPtr_ = new bMesh(bFaces, surf.localPoints());
755     // Clear edge storage
756     featurePoints_.setSize(0);
757     featureEdges_.setSize(0);
759     featureToEdge_.setSize(0);
760     edgeToFeature_.setSize(meshPtr_->nEdges());
761     edgeToFeature_ = -1;
763     featureSegments_.setSize(0);
765     extraEdges_.setSize(0);
769 void Foam::boundaryMesh::writeTriSurface(const fileName& fName) const
771     geometricSurfacePatchList surfPatches(patches_.size());
773     forAll(patches_, patchI)
774     {
775         const boundaryPatch& bp = patches_[patchI];
777         surfPatches[patchI] =
778             geometricSurfacePatch
779             (
780                 bp.physicalType(),
781                 bp.name(),
782                 patchI
783             );
784     }
786     //
787     // Simple triangulation.
788     //
790     // Get number of triangles per face
791     labelList nTris(mesh().size());
793     label totalNTris = getNTris(0, mesh().size(), nTris);
795     // Determine per face the starting triangle.
796     labelList startTri(mesh().size());
798     label triI = 0;
800     forAll(mesh(), faceI)
801     {
802         startTri[faceI] = triI;
804         triI += nTris[faceI];
805     }
807     // Triangulate
808     labelList triVerts(3*totalNTris);
810     triangulate(0, mesh().size(), totalNTris, triVerts);
812     // Convert to labelledTri
814     List<labelledTri> tris(totalNTris);
816     triI = 0;
818     forAll(patches_, patchI)
819     {
820         const boundaryPatch& bp = patches_[patchI];
822         forAll(bp, patchFaceI)
823         {
824             label faceI = bp.start() + patchFaceI;
826             label triVertI = 3*startTri[faceI];
828             for (label faceTriI = 0; faceTriI < nTris[faceI]; faceTriI++)
829             {
830                 label v0 = triVerts[triVertI++];
831                 label v1 = triVerts[triVertI++];
832                 label v2 = triVerts[triVertI++];
834                 tris[triI++] = labelledTri(v0, v1, v2, patchI);
835             }
836         }
837     }
839     triSurface surf(tris, surfPatches, mesh().points());
841     OFstream surfStream(fName);
843     surf.write(surfStream);
847 // Get index in this (boundaryMesh) of face nearest to each boundary face in
848 // pMesh.
849 // Origininally all triangles/faces of boundaryMesh would be bunged into
850 // one big octree. Problem was that faces on top of each other, differing
851 // only in sign of normal, could not be found separately. It would always
852 // find only one. We could detect that it was probably finding the wrong one
853 // (based on normal) but could not 'tell' the octree to retrieve the other
854 // one (since they occupy exactly the same space)
855 // So now faces get put into different octrees depending on normal.
856 // !It still will not be possible to differentiate between two faces on top
857 // of each other having the same normal
858 Foam::labelList Foam::boundaryMesh::getNearest
860     const primitiveMesh& pMesh,
861     const vector& searchSpan
862 ) const
865     // Divide faces into two bins acc. to normal
866     // - left of splitNormal
867     // - right ,,
868     DynamicList<label> leftFaces(mesh().size()/2);
869     DynamicList<label> rightFaces(mesh().size()/2);
871     forAll(mesh(), bFaceI)
872     {
873         scalar sign = mesh().faceNormals()[bFaceI] & splitNormal_;
875         if (sign > -1E-5)
876         {
877             rightFaces.append(bFaceI);
878         }
879         if (sign < 1E-5)
880         {
881             leftFaces.append(bFaceI);
882         }
883     }
885     leftFaces.shrink();
886     rightFaces.shrink();
888     if (debug)
889     {
890         Pout<< "getNearest :"
891             << " rightBin:" << rightFaces.size()
892             << " leftBin:" << leftFaces.size()
893             << endl;
894     }
896     uindirectPrimitivePatch leftPatch
897     (
898         UIndirectList<face>(mesh(), leftFaces),
899         mesh().points()
900     );
901     uindirectPrimitivePatch rightPatch
902     (
903         UIndirectList<face>(mesh(), rightFaces),
904         mesh().points()
905     );
908     // Overall bb
909     treeBoundBox overallBb(mesh().localPoints());
911     // Extend domain slightly (also makes it 3D if was 2D)
912     // Note asymmetry to avoid having faces align with octree cubes.
913     scalar tol = 1E-6 * overallBb.avgDim();
915     point& bbMin = overallBb.min();
916     bbMin.x() -= tol;
917     bbMin.y() -= tol;
918     bbMin.z() -= tol;
920     point& bbMax = overallBb.max();
921     bbMax.x() += 2*tol;
922     bbMax.y() += 2*tol;
923     bbMax.z() += 2*tol;
925     // Create the octrees
926     indexedOctree
927     <
928         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
929     > leftTree
930     (
931         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
932         (
933             false,          // cacheBb
934             leftPatch
935         ),
936         overallBb,
937         10, // maxLevel
938         10, // leafSize
939         3.0 // duplicity
940     );
941     indexedOctree
942     <
943         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
944     > rightTree
945     (
946         treeDataPrimitivePatch<face, UIndirectList, const pointField&>
947         (
948             false,          // cacheBb
949             rightPatch
950         ),
951         overallBb,
952         10, // maxLevel
953         10, // leafSize
954         3.0 // duplicity
955     );
957     if (debug)
958     {
959         Pout<< "getNearest : built trees" << endl;
960     }
963     const vectorField& ns = mesh().faceNormals();
966     //
967     // Search nearest triangle centre for every polyMesh boundary face
968     //
970     labelList nearestBFaceI(pMesh.nFaces() - pMesh.nInternalFaces());
972     treeBoundBox tightest;
974     const scalar searchDimSqr = magSqr(searchSpan);
976     forAll(nearestBFaceI, patchFaceI)
977     {
978         label meshFaceI = pMesh.nInternalFaces() + patchFaceI;
980         const point& ctr = pMesh.faceCentres()[meshFaceI];
982         if (debug && (patchFaceI % 1000) == 0)
983         {
984             Pout<< "getNearest : patchFace:" << patchFaceI
985                 << " meshFaceI:" << meshFaceI << " ctr:" << ctr << endl;
986         }
989         // Get normal from area vector
990         vector n = pMesh.faceAreas()[meshFaceI];
991         scalar area = mag(n);
992         n /= area;
994         scalar typDim = -GREAT;
995         const face& f = pMesh.faces()[meshFaceI];
997         forAll(f, fp)
998         {
999             typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
1000         }
1002         // Search right tree
1003         pointIndexHit rightInfo = rightTree.findNearest(ctr, searchDimSqr);
1005         // Search left tree. Note: could start from rightDist bounding box
1006         // instead of starting from top.
1007         pointIndexHit leftInfo = leftTree.findNearest(ctr, searchDimSqr);
1009         if (rightInfo.hit())
1010         {
1011             if (leftInfo.hit())
1012             {
1013                 // Found in both trees. Compare normals.
1014                 label rightFaceI = rightFaces[rightInfo.index()];
1015                 label leftFaceI = leftFaces[leftInfo.index()];
1017                 label rightDist = mag(rightInfo.hitPoint()-ctr);
1018                 label leftDist = mag(leftInfo.hitPoint()-ctr);
1020                 scalar rightSign = n & ns[rightFaceI];
1021                 scalar leftSign = n & ns[leftFaceI];
1023                 if
1024                 (
1025                     (rightSign > 0 && leftSign > 0)
1026                  || (rightSign < 0 && leftSign < 0)
1027                 )
1028                 {
1029                     // Both same sign. Choose nearest.
1030                     if (rightDist < leftDist)
1031                     {
1032                         nearestBFaceI[patchFaceI] = rightFaceI;
1033                     }
1034                     else
1035                     {
1036                         nearestBFaceI[patchFaceI] = leftFaceI;
1037                     }
1038                 }
1039                 else
1040                 {
1041                     // Differing sign.
1042                     // - if both near enough choose one with correct sign
1043                     // - otherwise choose nearest.
1045                     // Get local dimension as max of distance between ctr and
1046                     // any face vertex.
1048                     typDim *= distanceTol_;
1050                     if (rightDist < typDim && leftDist < typDim)
1051                     {
1052                         // Different sign and nearby. Choosing matching normal
1053                         if (rightSign > 0)
1054                         {
1055                             nearestBFaceI[patchFaceI] = rightFaceI;
1056                         }
1057                         else
1058                         {
1059                             nearestBFaceI[patchFaceI] = leftFaceI;
1060                         }
1061                     }
1062                     else
1063                     {
1064                         // Different sign but faraway. Choosing nearest.
1065                         if (rightDist < leftDist)
1066                         {
1067                             nearestBFaceI[patchFaceI] = rightFaceI;
1068                         }
1069                         else
1070                         {
1071                             nearestBFaceI[patchFaceI] = leftFaceI;
1072                         }
1073                     }
1074                 }
1075             }
1076             else
1077             {
1078                 // Found in right but not in left. Choose right regardless if
1079                 // correct sign. Note: do we want this?
1080                 label rightFaceI = rightFaces[rightInfo.index()];
1081                 nearestBFaceI[patchFaceI] = rightFaceI;
1082             }
1083         }
1084         else
1085         {
1086             // No face found in right tree.
1088             if (leftInfo.hit())
1089             {
1090                 // Found in left but not in right. Choose left regardless if
1091                 // correct sign. Note: do we want this?
1092                 nearestBFaceI[patchFaceI] = leftFaces[leftInfo.index()];
1093             }
1094             else
1095             {
1096                 // No face found in left tree.
1097                 nearestBFaceI[patchFaceI] = -1;
1098             }
1099         }
1100     }
1102     return nearestBFaceI;
1106 void Foam::boundaryMesh::patchify
1108     const labelList& nearest,
1109     const polyBoundaryMesh& oldPatches,
1110     polyMesh& newMesh
1111 ) const
1114     // 2 cases to be handled:
1115     // A- patches in boundaryMesh patches_
1116     // B- patches not in boundaryMesh patches_ but in polyMesh
1118     // Create maps from patch name to new patch index.
1119     HashTable<label> nameToIndex(2*patches_.size());
1121     Map<word> indexToName(2*patches_.size());
1124     label nNewPatches = patches_.size();
1126     forAll(oldPatches, oldPatchI)
1127     {
1128         const polyPatch& patch = oldPatches[oldPatchI];
1130         label newPatchI = findPatchID(patch.name());
1132         if (newPatchI != -1)
1133         {
1134             nameToIndex.insert(patch.name(), newPatchI);
1136             indexToName.insert(newPatchI, patch.name());
1137         }
1138     }
1140     // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1141     // patches)
1142     forAll(patches_, bPatchI)
1143     {
1144         const boundaryPatch& bp = patches_[bPatchI];
1146         if (!nameToIndex.found(bp.name()))
1147         {
1148             nameToIndex.insert(bp.name(), bPatchI);
1150             indexToName.insert(bPatchI, bp.name());
1151         }
1152     }
1154     // Pass1:
1155     // Copy names&type of patches (with zero size) from old mesh as far as
1156     // possible. First patch created gets all boundary faces; all others get
1157     // zero faces (repatched later on). Exception is coupled patches which
1158     // keep their size.
1160     List<polyPatch*> newPatchPtrList(nNewPatches);
1162     label meshFaceI = newMesh.nInternalFaces();
1164     // First patch gets all non-coupled faces
1165     label facesToBeDone = newMesh.nFaces() - newMesh.nInternalFaces();
1167     forAll(patches_, bPatchI)
1168     {
1169         const boundaryPatch& bp = patches_[bPatchI];
1171         label newPatchI = nameToIndex[bp.name()];
1173         // Find corresponding patch in polyMesh
1174         label oldPatchI = findPatchID(oldPatches, bp.name());
1176         if (oldPatchI == -1)
1177         {
1178             // Newly created patch. Gets all or zero faces.
1179             if (debug)
1180             {
1181                 Pout<< "patchify : Creating new polyPatch:" << bp.name()
1182                     << " type:" << bp.physicalType() << endl;
1183             }
1185             newPatchPtrList[newPatchI] = polyPatch::New
1186             (
1187                 bp.physicalType(),
1188                 bp.name(),
1189                 facesToBeDone,
1190                 meshFaceI,
1191                 newPatchI,
1192                 newMesh.boundaryMesh()
1193             ).ptr();
1195             meshFaceI += facesToBeDone;
1197             // first patch gets all boundary faces; all others get 0.
1198             facesToBeDone = 0;
1199         }
1200         else
1201         {
1202             // Existing patch. Gets all or zero faces.
1203             const polyPatch& oldPatch = oldPatches[oldPatchI];
1205             if (debug)
1206             {
1207                 Pout<< "patchify : Cloning existing polyPatch:"
1208                     << oldPatch.name() << endl;
1209             }
1211             newPatchPtrList[newPatchI] = oldPatch.clone
1212             (
1213                 newMesh.boundaryMesh(),
1214                 newPatchI,
1215                 facesToBeDone,
1216                 meshFaceI
1217             ).ptr();
1219             meshFaceI += facesToBeDone;
1221             // first patch gets all boundary faces; all others get 0.
1222             facesToBeDone = 0;
1223         }
1224     }
1227     if (debug)
1228     {
1229         Pout<< "Patchify : new polyPatch list:" << endl;
1231         forAll(newPatchPtrList, patchI)
1232         {
1233             const polyPatch& newPatch = *newPatchPtrList[patchI];
1235             if (debug)
1236             {
1237                 Pout<< "polyPatch:" << newPatch.name() << endl
1238                     << "    type :" << newPatch.typeName << endl
1239                     << "    size :" << newPatch.size() << endl
1240                     << "    start:" << newPatch.start() << endl
1241                     << "    index:" << patchI << endl;
1242             }
1243         }
1244     }
1246     // Actually add new list of patches
1247     repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1248     polyMeshRepatcher.changePatches(newPatchPtrList);
1251     // Pass2:
1252     // Change patch type for face
1254     if (newPatchPtrList.size())
1255     {
1256         List<DynamicList<label> > patchFaces(nNewPatches);
1258         // Give reasonable estimate for size of patches
1259         label nAvgFaces =
1260             (newMesh.nFaces() - newMesh.nInternalFaces())
1261           / nNewPatches;
1263         forAll(patchFaces, newPatchI)
1264         {
1265             patchFaces[newPatchI].setCapacity(nAvgFaces);
1266         }
1268         //
1269         // Sort faces acc. to new patch index. Can loop over all old patches
1270         // since will contain all faces.
1271         //
1273         forAll(oldPatches, oldPatchI)
1274         {
1275             const polyPatch& patch = oldPatches[oldPatchI];
1277             forAll(patch, patchFaceI)
1278             {
1279                 // Put face into region given by nearest boundary face
1281                 label meshFaceI = patch.start() + patchFaceI;
1283                 label bFaceI = meshFaceI - newMesh.nInternalFaces();
1285                 patchFaces[whichPatch(nearest[bFaceI])].append(meshFaceI);
1286             }
1287         }
1289         forAll(patchFaces, newPatchI)
1290         {
1291             patchFaces[newPatchI].shrink();
1292         }
1295         // Change patch > 0. (since above we put all faces into the zeroth
1296         // patch)
1298         for (label newPatchI = 1; newPatchI < patchFaces.size(); newPatchI++)
1299         {
1300             const labelList& pFaces = patchFaces[newPatchI];
1302             forAll(pFaces, pFaceI)
1303             {
1304                 polyMeshRepatcher.changePatchID(pFaces[pFaceI], newPatchI);
1305             }
1306         }
1308         polyMeshRepatcher.repatch();
1309     }
1313 void Foam::boundaryMesh::setFeatureEdges(const scalar minCos)
1315     edgeToFeature_.setSize(mesh().nEdges());
1317     edgeToFeature_ = -1;
1319     // 1. Mark feature edges
1321     // Storage for edge labels that are features. Trim later.
1322     featureToEdge_.setSize(mesh().nEdges());
1324     label featureI = 0;
1326     if (minCos >= 0.9999)
1327     {
1328         // Select everything
1329         forAll(mesh().edges(), edgeI)
1330         {
1331             edgeToFeature_[edgeI] = featureI;
1332             featureToEdge_[featureI++] = edgeI;
1333         }
1334     }
1335     else
1336     {
1337         forAll(mesh().edges(), edgeI)
1338         {
1339             const labelList& eFaces = mesh().edgeFaces()[edgeI];
1341             if (eFaces.size() == 2)
1342             {
1343                 label face0I = eFaces[0];
1345                 label face1I = eFaces[1];
1347                 ////- Uncomment below code if you want to include patch
1348                 ////  boundaries in feature edges.
1349                 //if (whichPatch(face0I) != whichPatch(face1I))
1350                 //{
1351                 //    edgeToFeature_[edgeI] = featureI;
1352                 //    featureToEdge_[featureI++] = edgeI;
1353                 //}
1354                 //else
1355                 {
1356                     const vector& n0 = mesh().faceNormals()[face0I];
1358                     const vector& n1 = mesh().faceNormals()[face1I];
1360                     float cosAng = n0 & n1;
1362                     if (cosAng < minCos)
1363                     {
1364                         edgeToFeature_[edgeI] = featureI;
1365                         featureToEdge_[featureI++] = edgeI;
1366                     }
1367                 }
1368             }
1369             else
1370             {
1371                 //Should not occur: 0 or more than two faces
1372                 edgeToFeature_[edgeI] = featureI;
1373                 featureToEdge_[featureI++] = edgeI;
1374             }
1375         }
1376     }
1378     // Trim featureToEdge_ to actual number of edges.
1379     featureToEdge_.setSize(featureI);
1381     //
1382     // Compact edges i.e. relabel vertices.
1383     //
1385     featureEdges_.setSize(featureI);
1386     featurePoints_.setSize(mesh().nPoints());
1388     labelList featToMeshPoint(mesh().nPoints(), -1);
1390     label featPtI = 0;
1392     forAll(featureToEdge_, fEdgeI)
1393     {
1394         label edgeI = featureToEdge_[fEdgeI];
1396         const edge& e = mesh().edges()[edgeI];
1398         label start = featToMeshPoint[e.start()];
1400         if (start == -1)
1401         {
1402             featToMeshPoint[e.start()] = featPtI;
1404             featurePoints_[featPtI] = mesh().points()[e.start()];
1406             start = featPtI;
1408             featPtI++;
1409         }
1411         label end = featToMeshPoint[e.end()];
1413         if (end == -1)
1414         {
1415             featToMeshPoint[e.end()] = featPtI;
1417             featurePoints_[featPtI] = mesh().points()[e.end()];
1419             end = featPtI;
1421             featPtI++;
1422         }
1424         // Store with renumbered vertices.
1425         featureEdges_[fEdgeI] = edge(start, end);
1426     }
1428     // Compact points
1429     featurePoints_.setSize(featPtI);
1432     //
1433     // 2. Mark endpoints of feature segments. These are points with
1434     // != 2 feature edges connected.
1435     // Note: can add geometric constraint here as well that if 2 feature
1436     // edges the angle between them should be less than xxx.
1437     //
1439     boolList isFeaturePoint(mesh().nPoints(), false);
1441     forAll(featureToEdge_, featI)
1442     {
1443         label edgeI = featureToEdge_[featI];
1445         const edge& e = mesh().edges()[edgeI];
1447         if (nFeatureEdges(e.start()) != 2)
1448         {
1449             isFeaturePoint[e.start()] = true;
1450         }
1452         if (nFeatureEdges(e.end()) != 2)
1453         {
1454             isFeaturePoint[e.end()] = true;
1455         }
1456     }
1459     //
1460     // 3: Split feature edges into segments:
1461     // find point with not 2 feature edges -> start of feature segment
1462     //
1464     DynamicList<labelList> segments;
1467     boolList featVisited(featureToEdge_.size(), false);
1469     do
1470     {
1471         label startFeatI = -1;
1473         forAll(featVisited, featI)
1474         {
1475             if (!featVisited[featI])
1476             {
1477                 startFeatI = featI;
1479                 break;
1480             }
1481         }
1483         if (startFeatI == -1)
1484         {
1485             // No feature lines left.
1486             break;
1487         }
1489         segments.append
1490         (
1491             collectSegment
1492             (
1493                 isFeaturePoint,
1494                 featureToEdge_[startFeatI],
1495                 featVisited
1496             )
1497         );
1498     }
1499     while (true);
1502     //
1503     // Store in *this
1504     //
1505     featureSegments_.setSize(segments.size());
1507     forAll(featureSegments_, segmentI)
1508     {
1509         featureSegments_[segmentI] = segments[segmentI];
1510     }
1514 void Foam::boundaryMesh::setExtraEdges(const label edgeI)
1516     labelList minDistance(mesh().nEdges(), -1);
1518     // All edge labels encountered
1519     DynamicList<label> visitedEdges;
1521     // Floodfill from edgeI starting from distance 0. Stop at distance.
1522     markEdges(8, edgeI, 0, minDistance, visitedEdges);
1524     // Set edge labels to display
1525     extraEdges_.transfer(visitedEdges);
1529 Foam::label Foam::boundaryMesh::whichPatch(const label faceI) const
1531     forAll(patches_, patchI)
1532     {
1533         const boundaryPatch& bp = patches_[patchI];
1535         if ((faceI >= bp.start()) && (faceI < (bp.start() + bp.size())))
1536         {
1537             return patchI;
1538         }
1539     }
1541     FatalErrorIn("boundaryMesh::whichPatch(const label)")
1542         << "Cannot find face " << faceI << " in list of boundaryPatches "
1543         << patches_
1544         << abort(FatalError);
1546     return -1;
1550 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1552     forAll(patches_, patchI)
1553     {
1554         if (patches_[patchI].name() == patchName)
1555         {
1556             return patchI;
1557         }
1558     }
1560     return -1;
1564 void Foam::boundaryMesh::addPatch(const word& patchName)
1566     patches_.setSize(patches_.size() + 1);
1568     // Add empty patch at end of patch list.
1570     label patchI = patches_.size()-1;
1572     boundaryPatch* bpPtr = new boundaryPatch
1573     (
1574         patchName,
1575         patchI,
1576         0,
1577         mesh().size(),
1578         "empty"
1579     );
1581     patches_.set(patchI, bpPtr);
1583     if (debug)
1584     {
1585         Pout<< "addPatch : patches now:" << endl;
1587         forAll(patches_, patchI)
1588         {
1589             const boundaryPatch& bp = patches_[patchI];
1591             Pout<< "    name  : " << bp.name() << endl
1592                 << "    size  : " << bp.size() << endl
1593                 << "    start : " << bp.start() << endl
1594                 << "    type  : " << bp.physicalType() << endl
1595                 << endl;
1596         }
1597     }
1601 void Foam::boundaryMesh::deletePatch(const word& patchName)
1603     label delPatchI = findPatchID(patchName);
1605     if (delPatchI == -1)
1606     {
1607         FatalErrorIn("boundaryMesh::deletePatch(const word&")
1608             << "Can't find patch named " << patchName
1609             << abort(FatalError);
1610     }
1612     if (patches_[delPatchI].size())
1613     {
1614         FatalErrorIn("boundaryMesh::deletePatch(const word&")
1615             << "Trying to delete non-empty patch " << patchName
1616             << endl << "Current size:" << patches_[delPatchI].size()
1617             << abort(FatalError);
1618     }
1620     PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1622     for (label patchI = 0; patchI < delPatchI; patchI++)
1623     {
1624         newPatches.set(patchI, patches_[patchI].clone());
1625     }
1627     // Move patches down, starting from delPatchI.
1629     for (label patchI = delPatchI + 1; patchI < patches_.size(); patchI++)
1630     {
1631         newPatches.set(patchI - 1, patches_[patchI].clone());
1632     }
1634     patches_.clear();
1636     patches_ = newPatches;
1638     if (debug)
1639     {
1640         Pout<< "deletePatch : patches now:" << endl;
1642         forAll(patches_, patchI)
1643         {
1644             const boundaryPatch& bp = patches_[patchI];
1646             Pout<< "    name  : " << bp.name() << endl
1647                 << "    size  : " << bp.size() << endl
1648                 << "    start : " << bp.start() << endl
1649                 << "    type  : " << bp.physicalType() << endl
1650                 << endl;
1651         }
1652     }
1656 void Foam::boundaryMesh::changePatchType
1658     const word& patchName,
1659     const word& patchType
1662     label changeI = findPatchID(patchName);
1664     if (changeI == -1)
1665     {
1666         FatalErrorIn("boundaryMesh::changePatchType(const word&, const word&)")
1667             << "Can't find patch named " << patchName
1668             << abort(FatalError);
1669     }
1672     // Cause we can't reassign to individual PtrList elems ;-(
1673     // work on copy
1676     PtrList<boundaryPatch> newPatches(patches_.size());
1678     forAll(patches_, patchI)
1679     {
1680         if (patchI == changeI)
1681         {
1682             // Create copy but for type
1683             const boundaryPatch& oldBp = patches_[patchI];
1685             boundaryPatch* bpPtr = new boundaryPatch
1686             (
1687                 oldBp.name(),
1688                 oldBp.index(),
1689                 oldBp.size(),
1690                 oldBp.start(),
1691                 patchType
1692             );
1694             newPatches.set(patchI, bpPtr);
1695         }
1696         else
1697         {
1698             // Create copy
1699             newPatches.set(patchI, patches_[patchI].clone());
1700         }
1701     }
1703     patches_ = newPatches;
1707 void Foam::boundaryMesh::changeFaces
1709     const labelList& patchIDs,
1710     labelList& oldToNew
1713     if (patchIDs.size() != mesh().size())
1714     {
1715         FatalErrorIn("boundaryMesh::changeFaces(const labelList& patchIDs)")
1716             << "List of patchIDs not equal to number of faces." << endl
1717             << "PatchIDs size:" << patchIDs.size()
1718             << " nFaces::" << mesh().size()
1719             << abort(FatalError);
1720     }
1722     // Count number of faces for each patch
1724     labelList nFaces(patches_.size(), 0);
1726     forAll(patchIDs, faceI)
1727     {
1728         label patchID = patchIDs[faceI];
1730         if (patchID < 0 || patchID >= patches_.size())
1731         {
1732             FatalErrorIn("boundaryMesh::changeFaces(const labelList&)")
1733                 << "PatchID " << patchID << " out of range"
1734                 << abort(FatalError);
1735         }
1736         nFaces[patchID]++;
1737     }
1740     // Determine position in faces_ for each patch
1742     labelList startFace(patches_.size());
1744     startFace[0] = 0;
1746     for (label patchI = 1; patchI < patches_.size(); patchI++)
1747     {
1748         startFace[patchI] = startFace[patchI-1] + nFaces[patchI-1];
1749     }
1751     // Update patch info
1752     PtrList<boundaryPatch> newPatches(patches_.size());
1754     forAll(patches_, patchI)
1755     {
1756         const boundaryPatch& bp = patches_[patchI];
1758         newPatches.set
1759         (
1760             patchI,
1761             new boundaryPatch
1762             (
1763                 bp.name(),
1764                 patchI,
1765                 nFaces[patchI],
1766                 startFace[patchI],
1767                 bp.physicalType()
1768             )
1769         );
1770     }
1771     patches_ = newPatches;
1773     if (debug)
1774     {
1775         Pout<< "changeFaces : patches now:" << endl;
1777         forAll(patches_, patchI)
1778         {
1779             const boundaryPatch& bp = patches_[patchI];
1781             Pout<< "    name  : " << bp.name() << endl
1782                 << "    size  : " << bp.size() << endl
1783                 << "    start : " << bp.start() << endl
1784                 << "    type  : " << bp.physicalType() << endl
1785                 << endl;
1786         }
1787     }
1790     // Construct face mapping array
1791     oldToNew.setSize(patchIDs.size());
1793     forAll(patchIDs, faceI)
1794     {
1795         int patchID = patchIDs[faceI];
1797         oldToNew[faceI] = startFace[patchID]++;
1798     }
1800     // Copy faces into correct position and maintain label of original face
1801     faceList newFaces(mesh().size());
1803     labelList newMeshFace(mesh().size());
1805     forAll(oldToNew, faceI)
1806     {
1807         newFaces[oldToNew[faceI]] = mesh()[faceI];
1808         newMeshFace[oldToNew[faceI]] = meshFace_[faceI];
1809     }
1811     // Reconstruct 'mesh' from new faces and (copy of) existing points.
1812     bMesh* newMeshPtr_ = new bMesh(newFaces, mesh().points());
1814     // Reset meshFace_ to new ordering.
1815     meshFace_.transfer(newMeshFace);
1818     // Remove old PrimitivePatch on meshPtr_.
1819     clearOut();
1821     // And insert new 'mesh'.
1822     meshPtr_ = newMeshPtr_;
1826 Foam::label Foam::boundaryMesh::getNTris(const label faceI) const
1828     const face& f = mesh()[faceI];
1830     return f.nTriangles(mesh().points());
1834 Foam::label Foam::boundaryMesh::getNTris
1836     const label startFaceI,
1837     const label nFaces,
1838     labelList& nTris
1839 ) const
1841     label totalNTris = 0;
1843     nTris.setSize(nFaces);
1845     for (label i = 0; i < nFaces; i++)
1846     {
1847         label faceNTris = getNTris(startFaceI + i);
1849         nTris[i] = faceNTris;
1851         totalNTris += faceNTris;
1852     }
1853     return totalNTris;
1857 // Simple triangulation of face subset. Stores vertices in tris[] as three
1858 // consecutive vertices per triangle.
1859 void Foam::boundaryMesh::triangulate
1861     const label startFaceI,
1862     const label nFaces,
1863     const label totalNTris,
1864     labelList& triVerts
1865 ) const
1867     // Triangulate faces.
1868     triVerts.setSize(3*totalNTris);
1870     label vertI = 0;
1872     for (label i = 0; i < nFaces; i++)
1873     {
1874         label faceI = startFaceI + i;
1876         const face& f = mesh()[faceI];
1878         // Have face triangulate itself (results in faceList)
1879         faceList triFaces(f.nTriangles(mesh().points()));
1881         label nTri = 0;
1883         f.triangles(mesh().points(), nTri, triFaces);
1885         // Copy into triVerts
1887         forAll(triFaces, triFaceI)
1888         {
1889             const face& triF = triFaces[triFaceI];
1891             triVerts[vertI++] = triF[0];
1892             triVerts[vertI++] = triF[1];
1893             triVerts[vertI++] = triF[2];
1894         }
1895     }
1899 // Number of local points in subset.
1900 Foam::label Foam::boundaryMesh::getNPoints
1902     const label startFaceI,
1903     const label nFaces
1904 ) const
1906     SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1908     primitivePatch patch(patchFaces, mesh().points());
1910     return patch.nPoints();
1914 // Triangulation of face subset in local coords.
1915 void Foam::boundaryMesh::triangulateLocal
1917     const label startFaceI,
1918     const label nFaces,
1919     const label totalNTris,
1920     labelList& triVerts,
1921     labelList& localToGlobal
1922 ) const
1924     SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1926     primitivePatch patch(patchFaces, mesh().points());
1928     // Map from local to mesh().points() addressing
1929     localToGlobal = patch.meshPoints();
1931     // Triangulate patch faces.
1932     triVerts.setSize(3*totalNTris);
1934     label vertI = 0;
1936     for (label i = 0; i < nFaces; i++)
1937     {
1938         // Local face
1939         const face& f = patch.localFaces()[i];
1941         // Have face triangulate itself (results in faceList)
1942         faceList triFaces(f.nTriangles(patch.localPoints()));
1944         label nTri = 0;
1946         f.triangles(patch.localPoints(), nTri, triFaces);
1948         // Copy into triVerts
1950         forAll(triFaces, triFaceI)
1951         {
1952             const face& triF = triFaces[triFaceI];
1954             triVerts[vertI++] = triF[0];
1955             triVerts[vertI++] = triF[1];
1956             triVerts[vertI++] = triF[2];
1957         }
1958     }
1962 void Foam::boundaryMesh::markFaces
1964     const labelList& protectedEdges,
1965     const label seedFaceI,
1966     boolList& visited
1967 ) const
1969     boolList protectedEdge(mesh().nEdges(), false);
1971     forAll(protectedEdges, i)
1972     {
1973         protectedEdge[protectedEdges[i]] = true;
1974     }
1977     // Initialize zone for all faces to -1
1978     labelList currentZone(mesh().size(), -1);
1980     // Mark with 0 all faces reachable from seedFaceI
1981     markZone(protectedEdge, seedFaceI, 0, currentZone);
1983     // Set in visited all reached ones.
1984     visited.setSize(mesh().size());
1986     forAll(currentZone, faceI)
1987     {
1988         if (currentZone[faceI] == 0)
1989         {
1990             visited[faceI] = true;
1991         }
1992         else
1993         {
1994             visited[faceI] = false;
1995         }
1996     }
2000 // ************************************************************************* //