1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "boundaryMesh.H"
28 #include "objectRegistry.H"
31 #include "repatchPolyTopoChanger.H"
33 #include "indexedOctree.H"
34 #include "treeDataPrimitivePatch.H"
35 #include "triSurface.H"
36 #include "SortableList.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
58 const labelList& pEdges = mesh().pointEdges()[pointI];
60 forAll(pEdges, pEdgeI)
62 label edgeI = pEdges[pEdgeI];
64 if (edgeToFeature_[edgeI] != -1)
73 // Returns next feature edge connected to pointI
74 Foam::label Foam::boundaryMesh::nextFeatureEdge
80 const labelList& pEdges = mesh().pointEdges()[vertI];
82 forAll(pEdges, pEdgeI)
84 label nbrEdgeI = pEdges[pEdgeI];
86 if (nbrEdgeI != edgeI)
88 label featI = edgeToFeature_[nbrEdgeI];
101 // Finds connected feature edges, starting from startPointI and returns
102 // feature labels (not edge labels). Marks feature edges handled in
104 Foam::labelList Foam::boundaryMesh::collectSegment
106 const boolList& isFeaturePoint,
107 const label startEdgeI,
108 boolList& featVisited
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])
121 // Step to next feature edge
123 edgeI = nextFeatureEdge(edgeI, vertI);
125 if ((edgeI == -1) || (edgeI == startEdgeI))
130 // Step to next vertex on edge
132 const edge& e = mesh().edges()[edgeI];
134 vertI = e.otherVertex(vertI);
139 // edgeI : first edge on this segment
140 // vertI : one of the endpoints of this segment
142 // Start walking other way and storing edges as we go along.
145 // Untrimmed storage for current segment
146 labelList featLabels(featureEdges_.size());
148 label featLabelI = 0;
150 label initEdgeI = edgeI;
154 // Mark edge as visited
155 label featI = edgeToFeature_[edgeI];
159 FatalErrorIn("boundaryMesh::collectSegment")
160 << "Problem" << abort(FatalError);
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))
181 while (!isFeaturePoint[vertI]);
185 featLabels.setSize(featLabelI);
191 void Foam::boundaryMesh::markEdges
193 const label maxDistance,
195 const label distance,
196 labelList& minDistance,
197 DynamicList<label>& visited
200 if (distance < maxDistance)
202 // Don't do anything if reached beyond maxDistance.
204 if (minDistance[edgeI] == -1)
206 // First visit of edge. Store edge label.
207 visited.append(edgeI);
209 else if (minDistance[edgeI] <= distance)
211 // Already done this edge
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)
234 // Do edges connected to e.end
235 const labelList& endEdges = mesh().pointEdges()[e.end()];
237 forAll(endEdges, pEdgeI)
252 Foam::label Foam::boundaryMesh::findPatchID
254 const polyPatchList& patches,
255 const word& patchName
258 forAll(patches, patchI)
260 if (patches[patchI].name() == patchName)
270 Foam::wordList Foam::boundaryMesh::patchNames() const
272 wordList names(patches_.size());
274 forAll(patches_, patchI)
276 names[patchI] = patches_[patchI].name();
282 Foam::label Foam::boundaryMesh::whichPatch
284 const polyPatchList& patches,
288 forAll(patches, patchI)
290 const polyPatch& pp = patches[patchI];
292 if ((faceI >= pp.start()) && (faceI < (pp.start() + pp.size())))
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,
307 const labelList& changedFaces,
308 labelList& edgeRegion
311 labelList changedEdges(mesh().nEdges(), -1);
314 forAll(changedFaces, i)
316 label faceI = changedFaces[i];
318 const labelList& fEdges = mesh().faceEdges()[faceI];
320 forAll(fEdges, fEdgeI)
322 label edgeI = fEdges[fEdgeI];
324 if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
326 edgeRegion[edgeI] = region;
328 changedEdges[changedI++] = edgeI;
333 changedEdges.setSize(changedI);
339 // Reverse of faceToEdge: gets edges and returns faces
340 Foam::labelList Foam::boundaryMesh::edgeToFace
343 const labelList& changedEdges,
344 labelList& faceRegion
347 labelList changedFaces(mesh().size(), -1);
350 forAll(changedEdges, i)
352 label edgeI = changedEdges[i];
354 const labelList& eFaces = mesh().edgeFaces()[edgeI];
356 forAll(eFaces, eFaceI)
358 label faceI = eFaces[eFaceI];
360 if (faceRegion[faceI] == -1)
362 faceRegion[faceI] = region;
364 changedFaces[changedI++] = faceI;
369 changedFaces.setSize(changedI);
375 // Finds area, starting at faceI, delimited by borderEdge
376 void Foam::boundaryMesh::markZone
378 const boolList& borderEdge,
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);
396 changedEdges = faceToEdge
406 Pout<< "From changedFaces:" << changedFaces.size()
407 << " to changedEdges:" << changedEdges.size()
411 if (changedEdges.empty())
416 changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
420 Pout<< "From changedEdges:" << changedEdges.size()
421 << " to changedFaces:" << changedFaces.size()
425 if (changedFaces.empty())
433 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
436 Foam::boundaryMesh::boundaryMesh()
450 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
452 Foam::boundaryMesh::~boundaryMesh()
458 void Foam::boundaryMesh::clearOut()
469 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
471 void Foam::boundaryMesh::read(const polyMesh& mesh)
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);
486 // Collect all boundary faces.
487 forAll(mesh.boundaryMesh(), patchI)
489 const polyPatch& pp = mesh.boundaryMesh()[patchI];
504 // Collect all faces in global numbering.
505 forAll(pp, patchFaceI)
507 meshFace_[bFaceI] = pp.start() + patchFaceI;
509 bFaces[bFaceI] = pp[patchFaceI];
518 Pout<< "read : patches now:" << endl;
520 forAll(patches_, patchI)
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
533 // Construct single patch for all of boundary
536 // Temporary primitivePatch to calculate compact points & faces.
537 PrimitivePatch<face, List, const pointField&> globalPatch
543 // Store in local(compact) addressing
546 meshPtr_ = new bMesh(globalPatch.localFaces(), globalPatch.localPoints());
551 const bMesh& msh = *meshPtr_;
553 Pout<< "** Start of Faces **" << endl;
557 const face& f = msh[faceI];
559 point ctr(vector::zero);
563 ctr += msh.points()[f[fp]];
573 Pout<< "** End of Faces **" << endl;
575 Pout<< "** Start of Points **" << endl;
577 forAll(msh.points(), pointI)
580 << " coord:" << msh.points()[pointI]
584 Pout<< "** End of Points **" << endl;
587 // Clear edge storage
588 featurePoints_.setSize(0);
589 featureEdges_.setSize(0);
591 featureToEdge_.setSize(0);
592 edgeToFeature_.setSize(meshPtr_->nEdges());
595 featureSegments_.setSize(0);
597 extraEdges_.setSize(0);
601 void Foam::boundaryMesh::readTriSurface(const fileName& fName)
603 triSurface surf(fName);
610 // Sort according to region
611 SortableList<label> regions(surf.size());
615 regions[triI] = surf[triI].region();
619 // Determine region mapping.
620 Map<label> regionToBoundaryPatch;
622 label oldRegion = -1111;
623 label boundPatch = 0;
627 if (regions[i] != oldRegion)
629 regionToBoundaryPatch.insert(regions[i], boundPatch);
631 oldRegion = regions[i];
636 const geometricSurfacePatchList& surfPatches = surf.patches();
640 if (surfPatches.size() == regionToBoundaryPatch.size())
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)
650 const geometricSurfacePatch& surfPatch = surfPatches[patchI];
661 surfPatch.geometricType()
668 // There are not enough surface patches. Make up my own.
670 patches_.setSize(regionToBoundaryPatch.size());
672 forAll(patches_, patchI)
679 "patch" + name(patchI),
690 // Copy according into bFaces according to regions
693 const labelList& indices = regions.indices();
695 faceList bFaces(surf.size());
697 meshFace_.setSize(surf.size());
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)
714 label triI = indices[indexI];
716 const labelledTri& tri = surf.localFaces()[triI];
718 if (tri.region() != surfRegion)
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()
736 meshFace_[bFaceI] = triI;
738 bFaces[bFaceI++] = face(tri);
742 boundaryPatch& bp = patches_[foamRegion];
744 bp.size() = bFaceI - startFaceI;
745 bp.start() = startFaceI;
748 // Construct single primitivePatch for all of boundary
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());
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)
776 const boundaryPatch& bp = patches_[patchI];
778 surfPatches[patchI] =
779 geometricSurfacePatch
788 // Simple triangulation.
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());
801 forAll(mesh(), faceI)
803 startTri[faceI] = triI;
805 triI += nTris[faceI];
809 labelList triVerts(3*totalNTris);
811 triangulate(0, mesh().size(), totalNTris, triVerts);
813 // Convert to labelledTri
815 List<labelledTri> tris(totalNTris);
819 forAll(patches_, patchI)
821 const boundaryPatch& bp = patches_[patchI];
823 forAll(bp, patchFaceI)
825 label faceI = bp.start() + patchFaceI;
827 label triVertI = 3*startTri[faceI];
829 for (label faceTriI = 0; faceTriI < nTris[faceI]; faceTriI++)
831 label v0 = triVerts[triVertI++];
832 label v1 = triVerts[triVertI++];
833 label v2 = triVerts[triVertI++];
835 tris[triI++] = labelledTri(v0, v1, v2, patchI);
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
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
866 // Divide faces into two bins acc. to normal
867 // - left of splitNormal
869 DynamicList<label> leftFaces(mesh().size()/2);
870 DynamicList<label> rightFaces(mesh().size()/2);
872 forAll(mesh(), bFaceI)
874 scalar sign = mesh().faceNormals()[bFaceI] & splitNormal_;
878 rightFaces.append(bFaceI);
882 leftFaces.append(bFaceI);
891 Pout<< "getNearest :"
892 << " rightBin:" << rightFaces.size()
893 << " leftBin:" << leftFaces.size()
897 uindirectPrimitivePatch leftPatch
899 UIndirectList<face>(mesh(), leftFaces),
902 uindirectPrimitivePatch rightPatch
904 UIndirectList<face>(mesh(), rightFaces),
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();
921 point& bbMax = overallBb.max();
926 // Create the octrees
929 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
932 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
944 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
947 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
960 Pout<< "getNearest : built trees" << endl;
964 const vectorField& ns = mesh().faceNormals();
968 // Search nearest triangle centre for every polyMesh boundary face
971 labelList nearestBFaceI(pMesh.nFaces() - pMesh.nInternalFaces());
973 treeBoundBox tightest;
975 const scalar searchDimSqr = magSqr(searchSpan);
977 forAll(nearestBFaceI, patchFaceI)
979 label meshFaceI = pMesh.nInternalFaces() + patchFaceI;
981 const point& ctr = pMesh.faceCentres()[meshFaceI];
983 if (debug && (patchFaceI % 1000) == 0)
985 Pout<< "getNearest : patchFace:" << patchFaceI
986 << " meshFaceI:" << meshFaceI << " ctr:" << ctr << endl;
990 // Get normal from area vector
991 vector n = pMesh.faceAreas()[meshFaceI];
992 scalar area = mag(n);
995 scalar typDim = -GREAT;
996 const face& f = pMesh.faces()[meshFaceI];
1000 typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
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())
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];
1026 (rightSign > 0 && leftSign > 0)
1027 || (rightSign < 0 && leftSign < 0)
1030 // Both same sign. Choose nearest.
1031 if (rightDist < leftDist)
1033 nearestBFaceI[patchFaceI] = rightFaceI;
1037 nearestBFaceI[patchFaceI] = leftFaceI;
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
1049 typDim *= distanceTol_;
1051 if (rightDist < typDim && leftDist < typDim)
1053 // Different sign and nearby. Choosing matching normal
1056 nearestBFaceI[patchFaceI] = rightFaceI;
1060 nearestBFaceI[patchFaceI] = leftFaceI;
1065 // Different sign but faraway. Choosing nearest.
1066 if (rightDist < leftDist)
1068 nearestBFaceI[patchFaceI] = rightFaceI;
1072 nearestBFaceI[patchFaceI] = leftFaceI;
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;
1087 // No face found in right tree.
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()];
1097 // No face found in left tree.
1098 nearestBFaceI[patchFaceI] = -1;
1103 return nearestBFaceI;
1107 void Foam::boundaryMesh::patchify
1109 const labelList& nearest,
1110 const polyBoundaryMesh& oldPatches,
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)
1129 const polyPatch& patch = oldPatches[oldPatchI];
1131 label newPatchI = findPatchID(patch.name());
1133 if (newPatchI != -1)
1135 nameToIndex.insert(patch.name(), newPatchI);
1137 indexToName.insert(newPatchI, patch.name());
1141 // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1143 forAll(patches_, bPatchI)
1145 const boundaryPatch& bp = patches_[bPatchI];
1147 if (!nameToIndex.found(bp.name()))
1149 nameToIndex.insert(bp.name(), bPatchI);
1151 indexToName.insert(bPatchI, bp.name());
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
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)
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)
1179 // Newly created patch. Gets all or zero faces.
1182 Pout<< "patchify : Creating new polyPatch:" << bp.name()
1183 << " type:" << bp.physicalType() << endl;
1186 newPatchPtrList[newPatchI] = polyPatch::New
1193 newMesh.boundaryMesh()
1196 meshFaceI += facesToBeDone;
1198 // first patch gets all boundary faces; all others get 0.
1203 // Existing patch. Gets all or zero faces.
1204 const polyPatch& oldPatch = oldPatches[oldPatchI];
1208 Pout<< "patchify : Cloning existing polyPatch:"
1209 << oldPatch.name() << endl;
1212 newPatchPtrList[newPatchI] = oldPatch.clone
1214 newMesh.boundaryMesh(),
1220 meshFaceI += facesToBeDone;
1222 // first patch gets all boundary faces; all others get 0.
1230 Pout<< "Patchify : new polyPatch list:" << endl;
1232 forAll(newPatchPtrList, patchI)
1234 const polyPatch& newPatch = *newPatchPtrList[patchI];
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;
1247 // Actually add new list of patches
1248 repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1249 polyMeshRepatcher.changePatches(newPatchPtrList);
1253 // Change patch type for face
1255 if (newPatchPtrList.size())
1257 List<DynamicList<label> > patchFaces(nNewPatches);
1259 // Give reasonable estimate for size of patches
1261 (newMesh.nFaces() - newMesh.nInternalFaces())
1264 forAll(patchFaces, newPatchI)
1266 patchFaces[newPatchI].setCapacity(nAvgFaces);
1270 // Sort faces acc. to new patch index. Can loop over all old patches
1271 // since will contain all faces.
1274 forAll(oldPatches, oldPatchI)
1276 const polyPatch& patch = oldPatches[oldPatchI];
1278 forAll(patch, patchFaceI)
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);
1290 forAll(patchFaces, newPatchI)
1292 patchFaces[newPatchI].shrink();
1296 // Change patch > 0. (since above we put all faces into the zeroth
1299 for (label newPatchI = 1; newPatchI < patchFaces.size(); newPatchI++)
1301 const labelList& pFaces = patchFaces[newPatchI];
1303 forAll(pFaces, pFaceI)
1305 polyMeshRepatcher.changePatchID(pFaces[pFaceI], newPatchI);
1309 polyMeshRepatcher.repatch();
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());
1327 if (minCos >= 0.9999)
1329 // Select everything
1330 forAll(mesh().edges(), edgeI)
1332 edgeToFeature_[edgeI] = featureI;
1333 featureToEdge_[featureI++] = edgeI;
1338 forAll(mesh().edges(), edgeI)
1340 const labelList& eFaces = mesh().edgeFaces()[edgeI];
1342 if (eFaces.size() == 2)
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))
1352 // edgeToFeature_[edgeI] = featureI;
1353 // featureToEdge_[featureI++] = edgeI;
1357 const vector& n0 = mesh().faceNormals()[face0I];
1359 const vector& n1 = mesh().faceNormals()[face1I];
1361 float cosAng = n0 & n1;
1363 if (cosAng < minCos)
1365 edgeToFeature_[edgeI] = featureI;
1366 featureToEdge_[featureI++] = edgeI;
1372 //Should not occur: 0 or more than two faces
1373 edgeToFeature_[edgeI] = featureI;
1374 featureToEdge_[featureI++] = edgeI;
1379 // Trim featureToEdge_ to actual number of edges.
1380 featureToEdge_.setSize(featureI);
1383 // Compact edges i.e. relabel vertices.
1386 featureEdges_.setSize(featureI);
1387 featurePoints_.setSize(mesh().nPoints());
1389 labelList featToMeshPoint(mesh().nPoints(), -1);
1393 forAll(featureToEdge_, fEdgeI)
1395 label edgeI = featureToEdge_[fEdgeI];
1397 const edge& e = mesh().edges()[edgeI];
1399 label start = featToMeshPoint[e.start()];
1403 featToMeshPoint[e.start()] = featPtI;
1405 featurePoints_[featPtI] = mesh().points()[e.start()];
1412 label end = featToMeshPoint[e.end()];
1416 featToMeshPoint[e.end()] = featPtI;
1418 featurePoints_[featPtI] = mesh().points()[e.end()];
1425 // Store with renumbered vertices.
1426 featureEdges_[fEdgeI] = edge(start, end);
1430 featurePoints_.setSize(featPtI);
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.
1440 boolList isFeaturePoint(mesh().nPoints(), false);
1442 forAll(featureToEdge_, featI)
1444 label edgeI = featureToEdge_[featI];
1446 const edge& e = mesh().edges()[edgeI];
1448 if (nFeatureEdges(e.start()) != 2)
1450 isFeaturePoint[e.start()] = true;
1453 if (nFeatureEdges(e.end()) != 2)
1455 isFeaturePoint[e.end()] = true;
1461 // 3: Split feature edges into segments:
1462 // find point with not 2 feature edges -> start of feature segment
1465 DynamicList<labelList> segments;
1468 boolList featVisited(featureToEdge_.size(), false);
1472 label startFeatI = -1;
1474 forAll(featVisited, featI)
1476 if (!featVisited[featI])
1484 if (startFeatI == -1)
1486 // No feature lines left.
1495 featureToEdge_[startFeatI],
1506 featureSegments_.setSize(segments.size());
1508 forAll(featureSegments_, segmentI)
1510 featureSegments_[segmentI] = segments[segmentI];
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)
1534 const boundaryPatch& bp = patches_[patchI];
1536 if ((faceI >= bp.start()) && (faceI < (bp.start() + bp.size())))
1542 FatalErrorIn("boundaryMesh::whichPatch(const label)")
1543 << "Cannot find face " << faceI << " in list of boundaryPatches "
1545 << abort(FatalError);
1551 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1553 forAll(patches_, patchI)
1555 if (patches_[patchI].name() == patchName)
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
1582 patches_.set(patchI, bpPtr);
1586 Pout<< "addPatch : patches now:" << endl;
1588 forAll(patches_, patchI)
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
1602 void Foam::boundaryMesh::deletePatch(const word& patchName)
1604 label delPatchI = findPatchID(patchName);
1606 if (delPatchI == -1)
1608 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1609 << "Can't find patch named " << patchName
1610 << abort(FatalError);
1613 if (patches_[delPatchI].size())
1615 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1616 << "Trying to delete non-empty patch " << patchName
1617 << endl << "Current size:" << patches_[delPatchI].size()
1618 << abort(FatalError);
1621 PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1623 for (label patchI = 0; patchI < delPatchI; patchI++)
1625 newPatches.set(patchI, patches_[patchI].clone());
1628 // Move patches down, starting from delPatchI.
1630 for (label patchI = delPatchI + 1; patchI < patches_.size(); patchI++)
1632 newPatches.set(patchI - 1, patches_[patchI].clone());
1637 patches_ = newPatches;
1641 Pout<< "deletePatch : patches now:" << endl;
1643 forAll(patches_, patchI)
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
1657 void Foam::boundaryMesh::changePatchType
1659 const word& patchName,
1660 const word& patchType
1663 label changeI = findPatchID(patchName);
1667 FatalErrorIn("boundaryMesh::changePatchType(const word&, const word&)")
1668 << "Can't find patch named " << patchName
1669 << abort(FatalError);
1673 // Cause we can't reassign to individual PtrList elems ;-(
1677 PtrList<boundaryPatch> newPatches(patches_.size());
1679 forAll(patches_, patchI)
1681 if (patchI == changeI)
1683 // Create copy but for type
1684 const boundaryPatch& oldBp = patches_[patchI];
1686 boundaryPatch* bpPtr = new boundaryPatch
1695 newPatches.set(patchI, bpPtr);
1700 newPatches.set(patchI, patches_[patchI].clone());
1704 patches_ = newPatches;
1708 void Foam::boundaryMesh::changeFaces
1710 const labelList& patchIDs,
1714 if (patchIDs.size() != mesh().size())
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);
1723 // Count number of faces for each patch
1725 labelList nFaces(patches_.size(), 0);
1727 forAll(patchIDs, faceI)
1729 label patchID = patchIDs[faceI];
1731 if (patchID < 0 || patchID >= patches_.size())
1733 FatalErrorIn("boundaryMesh::changeFaces(const labelList&)")
1734 << "PatchID " << patchID << " out of range"
1735 << abort(FatalError);
1741 // Determine position in faces_ for each patch
1743 labelList startFace(patches_.size());
1747 for (label patchI = 1; patchI < patches_.size(); patchI++)
1749 startFace[patchI] = startFace[patchI-1] + nFaces[patchI-1];
1752 // Update patch info
1753 PtrList<boundaryPatch> newPatches(patches_.size());
1755 forAll(patches_, patchI)
1757 const boundaryPatch& bp = patches_[patchI];
1772 patches_ = newPatches;
1776 Pout<< "changeFaces : patches now:" << endl;
1778 forAll(patches_, patchI)
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
1791 // Construct face mapping array
1792 oldToNew.setSize(patchIDs.size());
1794 forAll(patchIDs, faceI)
1796 int patchID = patchIDs[faceI];
1798 oldToNew[faceI] = startFace[patchID]++;
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)
1808 newFaces[oldToNew[faceI]] = mesh()[faceI];
1809 newMeshFace[oldToNew[faceI]] = meshFace_[faceI];
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_.
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,
1842 label totalNTris = 0;
1844 nTris.setSize(nFaces);
1846 for (label i = 0; i < nFaces; i++)
1848 label faceNTris = getNTris(startFaceI + i);
1850 nTris[i] = faceNTris;
1852 totalNTris += faceNTris;
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,
1864 const label totalNTris,
1868 // Triangulate faces.
1869 triVerts.setSize(3*totalNTris);
1873 for (label i = 0; i < nFaces; i++)
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()));
1884 f.triangles(mesh().points(), nTri, triFaces);
1886 // Copy into triVerts
1888 forAll(triFaces, triFaceI)
1890 const face& triF = triFaces[triFaceI];
1892 triVerts[vertI++] = triF[0];
1893 triVerts[vertI++] = triF[1];
1894 triVerts[vertI++] = triF[2];
1900 // Number of local points in subset.
1901 Foam::label Foam::boundaryMesh::getNPoints
1903 const label startFaceI,
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,
1920 const label totalNTris,
1921 labelList& triVerts,
1922 labelList& localToGlobal
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);
1937 for (label i = 0; i < nFaces; i++)
1940 const face& f = patch.localFaces()[i];
1942 // Have face triangulate itself (results in faceList)
1943 faceList triFaces(f.nTriangles(patch.localPoints()));
1947 f.triangles(patch.localPoints(), nTri, triFaces);
1949 // Copy into triVerts
1951 forAll(triFaces, triFaceI)
1953 const face& triF = triFaces[triFaceI];
1955 triVerts[vertI++] = triF[0];
1956 triVerts[vertI++] = triF[1];
1957 triVerts[vertI++] = triF[2];
1963 void Foam::boundaryMesh::markFaces
1965 const labelList& protectedEdges,
1966 const label seedFaceI,
1970 boolList protectedEdge(mesh().nEdges(), false);
1972 forAll(protectedEdges, i)
1974 protectedEdge[protectedEdges[i]] = true;
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)
1989 if (currentZone[faceI] == 0)
1991 visited[faceI] = true;
1995 visited[faceI] = false;
2001 // ************************************************************************* //