1 /*---------------------------------------------------------------------------*\
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 -------------------------------------------------------------------------------
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"
30 #include "repatchPolyTopoChanger.H"
32 #include "indexedOctree.H"
33 #include "treeDataPrimitivePatch.H"
34 #include "triSurface.H"
35 #include "SortableList.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
57 const labelList& pEdges = mesh().pointEdges()[pointI];
59 forAll(pEdges, pEdgeI)
61 label edgeI = pEdges[pEdgeI];
63 if (edgeToFeature_[edgeI] != -1)
72 // Returns next feature edge connected to pointI
73 Foam::label Foam::boundaryMesh::nextFeatureEdge
79 const labelList& pEdges = mesh().pointEdges()[vertI];
81 forAll(pEdges, pEdgeI)
83 label nbrEdgeI = pEdges[pEdgeI];
85 if (nbrEdgeI != edgeI)
87 label featI = edgeToFeature_[nbrEdgeI];
100 // Finds connected feature edges, starting from startPointI and returns
101 // feature labels (not edge labels). Marks feature edges handled in
103 Foam::labelList Foam::boundaryMesh::collectSegment
105 const boolList& isFeaturePoint,
106 const label startEdgeI,
107 boolList& featVisited
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])
120 // Step to next feature edge
122 edgeI = nextFeatureEdge(edgeI, vertI);
124 if ((edgeI == -1) || (edgeI == startEdgeI))
129 // Step to next vertex on edge
131 const edge& e = mesh().edges()[edgeI];
133 vertI = e.otherVertex(vertI);
138 // edgeI : first edge on this segment
139 // vertI : one of the endpoints of this segment
141 // Start walking other way and storing edges as we go along.
144 // Untrimmed storage for current segment
145 labelList featLabels(featureEdges_.size());
147 label featLabelI = 0;
149 label initEdgeI = edgeI;
153 // Mark edge as visited
154 label featI = edgeToFeature_[edgeI];
158 FatalErrorIn("boundaryMesh::collectSegment")
159 << "Problem" << abort(FatalError);
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))
180 while (!isFeaturePoint[vertI]);
184 featLabels.setSize(featLabelI);
190 void Foam::boundaryMesh::markEdges
192 const label maxDistance,
194 const label distance,
195 labelList& minDistance,
196 DynamicList<label>& visited
199 if (distance < maxDistance)
201 // Don't do anything if reached beyond maxDistance.
203 if (minDistance[edgeI] == -1)
205 // First visit of edge. Store edge label.
206 visited.append(edgeI);
208 else if (minDistance[edgeI] <= distance)
210 // Already done this edge
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)
233 // Do edges connected to e.end
234 const labelList& endEdges = mesh().pointEdges()[e.end()];
236 forAll(endEdges, pEdgeI)
251 Foam::label Foam::boundaryMesh::findPatchID
253 const polyPatchList& patches,
254 const word& patchName
257 forAll(patches, patchI)
259 if (patches[patchI].name() == patchName)
269 Foam::wordList Foam::boundaryMesh::patchNames() const
271 wordList names(patches_.size());
273 forAll(patches_, patchI)
275 names[patchI] = patches_[patchI].name();
281 Foam::label Foam::boundaryMesh::whichPatch
283 const polyPatchList& patches,
287 forAll(patches, patchI)
289 const polyPatch& pp = patches[patchI];
291 if ((faceI >= pp.start()) && (faceI < (pp.start() + pp.size())))
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,
306 const labelList& changedFaces,
307 labelList& edgeRegion
310 labelList changedEdges(mesh().nEdges(), -1);
313 forAll(changedFaces, i)
315 label faceI = changedFaces[i];
317 const labelList& fEdges = mesh().faceEdges()[faceI];
319 forAll(fEdges, fEdgeI)
321 label edgeI = fEdges[fEdgeI];
323 if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
325 edgeRegion[edgeI] = region;
327 changedEdges[changedI++] = edgeI;
332 changedEdges.setSize(changedI);
338 // Reverse of faceToEdge: gets edges and returns faces
339 Foam::labelList Foam::boundaryMesh::edgeToFace
342 const labelList& changedEdges,
343 labelList& faceRegion
346 labelList changedFaces(mesh().size(), -1);
349 forAll(changedEdges, i)
351 label edgeI = changedEdges[i];
353 const labelList& eFaces = mesh().edgeFaces()[edgeI];
355 forAll(eFaces, eFaceI)
357 label faceI = eFaces[eFaceI];
359 if (faceRegion[faceI] == -1)
361 faceRegion[faceI] = region;
363 changedFaces[changedI++] = faceI;
368 changedFaces.setSize(changedI);
374 // Finds area, starting at faceI, delimited by borderEdge
375 void Foam::boundaryMesh::markZone
377 const boolList& borderEdge,
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);
395 changedEdges = faceToEdge
405 Pout<< "From changedFaces:" << changedFaces.size()
406 << " to changedEdges:" << changedEdges.size()
410 if (changedEdges.empty())
415 changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
419 Pout<< "From changedEdges:" << changedEdges.size()
420 << " to changedFaces:" << changedFaces.size()
424 if (changedFaces.empty())
432 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
435 Foam::boundaryMesh::boundaryMesh()
449 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
451 Foam::boundaryMesh::~boundaryMesh()
457 void Foam::boundaryMesh::clearOut()
468 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
470 void Foam::boundaryMesh::read(const polyMesh& mesh)
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);
485 // Collect all boundary faces.
486 forAll(mesh.boundaryMesh(), patchI)
488 const polyPatch& pp = mesh.boundaryMesh()[patchI];
503 // Collect all faces in global numbering.
504 forAll(pp, patchFaceI)
506 meshFace_[bFaceI] = pp.start() + patchFaceI;
508 bFaces[bFaceI] = pp[patchFaceI];
517 Pout<< "read : patches now:" << endl;
519 forAll(patches_, patchI)
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
532 // Construct single patch for all of boundary
535 // Temporary primitivePatch to calculate compact points & faces.
536 PrimitivePatch<face, List, const pointField&> globalPatch
542 // Store in local(compact) addressing
545 meshPtr_ = new bMesh(globalPatch.localFaces(), globalPatch.localPoints());
550 const bMesh& msh = *meshPtr_;
552 Pout<< "** Start of Faces **" << endl;
556 const face& f = msh[faceI];
558 point ctr(vector::zero);
562 ctr += msh.points()[f[fp]];
572 Pout<< "** End of Faces **" << endl;
574 Pout<< "** Start of Points **" << endl;
576 forAll(msh.points(), pointI)
579 << " coord:" << msh.points()[pointI]
583 Pout<< "** End of Points **" << endl;
586 // Clear edge storage
587 featurePoints_.setSize(0);
588 featureEdges_.setSize(0);
590 featureToEdge_.setSize(0);
591 edgeToFeature_.setSize(meshPtr_->nEdges());
594 featureSegments_.setSize(0);
596 extraEdges_.setSize(0);
600 void Foam::boundaryMesh::readTriSurface(const fileName& fName)
602 triSurface surf(fName);
609 // Sort according to region
610 SortableList<label> regions(surf.size());
614 regions[triI] = surf[triI].region();
618 // Determine region mapping.
619 Map<label> regionToBoundaryPatch;
621 label oldRegion = -1111;
622 label boundPatch = 0;
626 if (regions[i] != oldRegion)
628 regionToBoundaryPatch.insert(regions[i], boundPatch);
630 oldRegion = regions[i];
635 const geometricSurfacePatchList& surfPatches = surf.patches();
639 if (surfPatches.size() == regionToBoundaryPatch.size())
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)
649 const geometricSurfacePatch& surfPatch = surfPatches[patchI];
660 surfPatch.geometricType()
667 // There are not enough surface patches. Make up my own.
669 patches_.setSize(regionToBoundaryPatch.size());
671 forAll(patches_, patchI)
678 "patch" + name(patchI),
689 // Copy according into bFaces according to regions
692 const labelList& indices = regions.indices();
694 faceList bFaces(surf.size());
696 meshFace_.setSize(surf.size());
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)
713 label triI = indices[indexI];
715 const labelledTri& tri = surf.localFaces()[triI];
717 if (tri.region() != surfRegion)
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()
735 meshFace_[bFaceI] = triI;
737 bFaces[bFaceI++] = face(tri);
741 boundaryPatch& bp = patches_[foamRegion];
743 bp.size() = bFaceI - startFaceI;
744 bp.start() = startFaceI;
747 // Construct single primitivePatch for all of boundary
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());
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)
775 const boundaryPatch& bp = patches_[patchI];
777 surfPatches[patchI] =
778 geometricSurfacePatch
787 // Simple triangulation.
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());
800 forAll(mesh(), faceI)
802 startTri[faceI] = triI;
804 triI += nTris[faceI];
808 labelList triVerts(3*totalNTris);
810 triangulate(0, mesh().size(), totalNTris, triVerts);
812 // Convert to labelledTri
814 List<labelledTri> tris(totalNTris);
818 forAll(patches_, patchI)
820 const boundaryPatch& bp = patches_[patchI];
822 forAll(bp, patchFaceI)
824 label faceI = bp.start() + patchFaceI;
826 label triVertI = 3*startTri[faceI];
828 for (label faceTriI = 0; faceTriI < nTris[faceI]; faceTriI++)
830 label v0 = triVerts[triVertI++];
831 label v1 = triVerts[triVertI++];
832 label v2 = triVerts[triVertI++];
834 tris[triI++] = labelledTri(v0, v1, v2, patchI);
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
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
865 // Divide faces into two bins acc. to normal
866 // - left of splitNormal
868 DynamicList<label> leftFaces(mesh().size()/2);
869 DynamicList<label> rightFaces(mesh().size()/2);
871 forAll(mesh(), bFaceI)
873 scalar sign = mesh().faceNormals()[bFaceI] & splitNormal_;
877 rightFaces.append(bFaceI);
881 leftFaces.append(bFaceI);
890 Pout<< "getNearest :"
891 << " rightBin:" << rightFaces.size()
892 << " leftBin:" << leftFaces.size()
896 uindirectPrimitivePatch leftPatch
898 UIndirectList<face>(mesh(), leftFaces),
901 uindirectPrimitivePatch rightPatch
903 UIndirectList<face>(mesh(), rightFaces),
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();
920 point& bbMax = overallBb.max();
925 // Create the octrees
928 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
931 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
943 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
946 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
959 Pout<< "getNearest : built trees" << endl;
963 const vectorField& ns = mesh().faceNormals();
967 // Search nearest triangle centre for every polyMesh boundary face
970 labelList nearestBFaceI(pMesh.nFaces() - pMesh.nInternalFaces());
972 treeBoundBox tightest;
974 const scalar searchDimSqr = magSqr(searchSpan);
976 forAll(nearestBFaceI, patchFaceI)
978 label meshFaceI = pMesh.nInternalFaces() + patchFaceI;
980 const point& ctr = pMesh.faceCentres()[meshFaceI];
982 if (debug && (patchFaceI % 1000) == 0)
984 Pout<< "getNearest : patchFace:" << patchFaceI
985 << " meshFaceI:" << meshFaceI << " ctr:" << ctr << endl;
989 // Get normal from area vector
990 vector n = pMesh.faceAreas()[meshFaceI];
991 scalar area = mag(n);
994 scalar typDim = -GREAT;
995 const face& f = pMesh.faces()[meshFaceI];
999 typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
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())
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];
1025 (rightSign > 0 && leftSign > 0)
1026 || (rightSign < 0 && leftSign < 0)
1029 // Both same sign. Choose nearest.
1030 if (rightDist < leftDist)
1032 nearestBFaceI[patchFaceI] = rightFaceI;
1036 nearestBFaceI[patchFaceI] = leftFaceI;
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
1048 typDim *= distanceTol_;
1050 if (rightDist < typDim && leftDist < typDim)
1052 // Different sign and nearby. Choosing matching normal
1055 nearestBFaceI[patchFaceI] = rightFaceI;
1059 nearestBFaceI[patchFaceI] = leftFaceI;
1064 // Different sign but faraway. Choosing nearest.
1065 if (rightDist < leftDist)
1067 nearestBFaceI[patchFaceI] = rightFaceI;
1071 nearestBFaceI[patchFaceI] = leftFaceI;
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;
1086 // No face found in right tree.
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()];
1096 // No face found in left tree.
1097 nearestBFaceI[patchFaceI] = -1;
1102 return nearestBFaceI;
1106 void Foam::boundaryMesh::patchify
1108 const labelList& nearest,
1109 const polyBoundaryMesh& oldPatches,
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)
1128 const polyPatch& patch = oldPatches[oldPatchI];
1130 label newPatchI = findPatchID(patch.name());
1132 if (newPatchI != -1)
1134 nameToIndex.insert(patch.name(), newPatchI);
1136 indexToName.insert(newPatchI, patch.name());
1140 // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1142 forAll(patches_, bPatchI)
1144 const boundaryPatch& bp = patches_[bPatchI];
1146 if (!nameToIndex.found(bp.name()))
1148 nameToIndex.insert(bp.name(), bPatchI);
1150 indexToName.insert(bPatchI, bp.name());
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
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)
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)
1178 // Newly created patch. Gets all or zero faces.
1181 Pout<< "patchify : Creating new polyPatch:" << bp.name()
1182 << " type:" << bp.physicalType() << endl;
1185 newPatchPtrList[newPatchI] = polyPatch::New
1192 newMesh.boundaryMesh()
1195 meshFaceI += facesToBeDone;
1197 // first patch gets all boundary faces; all others get 0.
1202 // Existing patch. Gets all or zero faces.
1203 const polyPatch& oldPatch = oldPatches[oldPatchI];
1207 Pout<< "patchify : Cloning existing polyPatch:"
1208 << oldPatch.name() << endl;
1211 newPatchPtrList[newPatchI] = oldPatch.clone
1213 newMesh.boundaryMesh(),
1219 meshFaceI += facesToBeDone;
1221 // first patch gets all boundary faces; all others get 0.
1229 Pout<< "Patchify : new polyPatch list:" << endl;
1231 forAll(newPatchPtrList, patchI)
1233 const polyPatch& newPatch = *newPatchPtrList[patchI];
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;
1246 // Actually add new list of patches
1247 repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1248 polyMeshRepatcher.changePatches(newPatchPtrList);
1252 // Change patch type for face
1254 if (newPatchPtrList.size())
1256 List<DynamicList<label> > patchFaces(nNewPatches);
1258 // Give reasonable estimate for size of patches
1260 (newMesh.nFaces() - newMesh.nInternalFaces())
1263 forAll(patchFaces, newPatchI)
1265 patchFaces[newPatchI].setCapacity(nAvgFaces);
1269 // Sort faces acc. to new patch index. Can loop over all old patches
1270 // since will contain all faces.
1273 forAll(oldPatches, oldPatchI)
1275 const polyPatch& patch = oldPatches[oldPatchI];
1277 forAll(patch, patchFaceI)
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);
1289 forAll(patchFaces, newPatchI)
1291 patchFaces[newPatchI].shrink();
1295 // Change patch > 0. (since above we put all faces into the zeroth
1298 for (label newPatchI = 1; newPatchI < patchFaces.size(); newPatchI++)
1300 const labelList& pFaces = patchFaces[newPatchI];
1302 forAll(pFaces, pFaceI)
1304 polyMeshRepatcher.changePatchID(pFaces[pFaceI], newPatchI);
1308 polyMeshRepatcher.repatch();
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());
1326 if (minCos >= 0.9999)
1328 // Select everything
1329 forAll(mesh().edges(), edgeI)
1331 edgeToFeature_[edgeI] = featureI;
1332 featureToEdge_[featureI++] = edgeI;
1337 forAll(mesh().edges(), edgeI)
1339 const labelList& eFaces = mesh().edgeFaces()[edgeI];
1341 if (eFaces.size() == 2)
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))
1351 // edgeToFeature_[edgeI] = featureI;
1352 // featureToEdge_[featureI++] = edgeI;
1356 const vector& n0 = mesh().faceNormals()[face0I];
1358 const vector& n1 = mesh().faceNormals()[face1I];
1360 float cosAng = n0 & n1;
1362 if (cosAng < minCos)
1364 edgeToFeature_[edgeI] = featureI;
1365 featureToEdge_[featureI++] = edgeI;
1371 //Should not occur: 0 or more than two faces
1372 edgeToFeature_[edgeI] = featureI;
1373 featureToEdge_[featureI++] = edgeI;
1378 // Trim featureToEdge_ to actual number of edges.
1379 featureToEdge_.setSize(featureI);
1382 // Compact edges i.e. relabel vertices.
1385 featureEdges_.setSize(featureI);
1386 featurePoints_.setSize(mesh().nPoints());
1388 labelList featToMeshPoint(mesh().nPoints(), -1);
1392 forAll(featureToEdge_, fEdgeI)
1394 label edgeI = featureToEdge_[fEdgeI];
1396 const edge& e = mesh().edges()[edgeI];
1398 label start = featToMeshPoint[e.start()];
1402 featToMeshPoint[e.start()] = featPtI;
1404 featurePoints_[featPtI] = mesh().points()[e.start()];
1411 label end = featToMeshPoint[e.end()];
1415 featToMeshPoint[e.end()] = featPtI;
1417 featurePoints_[featPtI] = mesh().points()[e.end()];
1424 // Store with renumbered vertices.
1425 featureEdges_[fEdgeI] = edge(start, end);
1429 featurePoints_.setSize(featPtI);
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.
1439 boolList isFeaturePoint(mesh().nPoints(), false);
1441 forAll(featureToEdge_, featI)
1443 label edgeI = featureToEdge_[featI];
1445 const edge& e = mesh().edges()[edgeI];
1447 if (nFeatureEdges(e.start()) != 2)
1449 isFeaturePoint[e.start()] = true;
1452 if (nFeatureEdges(e.end()) != 2)
1454 isFeaturePoint[e.end()] = true;
1460 // 3: Split feature edges into segments:
1461 // find point with not 2 feature edges -> start of feature segment
1464 DynamicList<labelList> segments;
1467 boolList featVisited(featureToEdge_.size(), false);
1471 label startFeatI = -1;
1473 forAll(featVisited, featI)
1475 if (!featVisited[featI])
1483 if (startFeatI == -1)
1485 // No feature lines left.
1494 featureToEdge_[startFeatI],
1505 featureSegments_.setSize(segments.size());
1507 forAll(featureSegments_, segmentI)
1509 featureSegments_[segmentI] = segments[segmentI];
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)
1533 const boundaryPatch& bp = patches_[patchI];
1535 if ((faceI >= bp.start()) && (faceI < (bp.start() + bp.size())))
1541 FatalErrorIn("boundaryMesh::whichPatch(const label)")
1542 << "Cannot find face " << faceI << " in list of boundaryPatches "
1544 << abort(FatalError);
1550 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1552 forAll(patches_, patchI)
1554 if (patches_[patchI].name() == patchName)
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
1581 patches_.set(patchI, bpPtr);
1585 Pout<< "addPatch : patches now:" << endl;
1587 forAll(patches_, patchI)
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
1601 void Foam::boundaryMesh::deletePatch(const word& patchName)
1603 label delPatchI = findPatchID(patchName);
1605 if (delPatchI == -1)
1607 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1608 << "Can't find patch named " << patchName
1609 << abort(FatalError);
1612 if (patches_[delPatchI].size())
1614 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1615 << "Trying to delete non-empty patch " << patchName
1616 << endl << "Current size:" << patches_[delPatchI].size()
1617 << abort(FatalError);
1620 PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1622 for (label patchI = 0; patchI < delPatchI; patchI++)
1624 newPatches.set(patchI, patches_[patchI].clone());
1627 // Move patches down, starting from delPatchI.
1629 for (label patchI = delPatchI + 1; patchI < patches_.size(); patchI++)
1631 newPatches.set(patchI - 1, patches_[patchI].clone());
1636 patches_ = newPatches;
1640 Pout<< "deletePatch : patches now:" << endl;
1642 forAll(patches_, patchI)
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
1656 void Foam::boundaryMesh::changePatchType
1658 const word& patchName,
1659 const word& patchType
1662 label changeI = findPatchID(patchName);
1666 FatalErrorIn("boundaryMesh::changePatchType(const word&, const word&)")
1667 << "Can't find patch named " << patchName
1668 << abort(FatalError);
1672 // Cause we can't reassign to individual PtrList elems ;-(
1676 PtrList<boundaryPatch> newPatches(patches_.size());
1678 forAll(patches_, patchI)
1680 if (patchI == changeI)
1682 // Create copy but for type
1683 const boundaryPatch& oldBp = patches_[patchI];
1685 boundaryPatch* bpPtr = new boundaryPatch
1694 newPatches.set(patchI, bpPtr);
1699 newPatches.set(patchI, patches_[patchI].clone());
1703 patches_ = newPatches;
1707 void Foam::boundaryMesh::changeFaces
1709 const labelList& patchIDs,
1713 if (patchIDs.size() != mesh().size())
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);
1722 // Count number of faces for each patch
1724 labelList nFaces(patches_.size(), 0);
1726 forAll(patchIDs, faceI)
1728 label patchID = patchIDs[faceI];
1730 if (patchID < 0 || patchID >= patches_.size())
1732 FatalErrorIn("boundaryMesh::changeFaces(const labelList&)")
1733 << "PatchID " << patchID << " out of range"
1734 << abort(FatalError);
1740 // Determine position in faces_ for each patch
1742 labelList startFace(patches_.size());
1746 for (label patchI = 1; patchI < patches_.size(); patchI++)
1748 startFace[patchI] = startFace[patchI-1] + nFaces[patchI-1];
1751 // Update patch info
1752 PtrList<boundaryPatch> newPatches(patches_.size());
1754 forAll(patches_, patchI)
1756 const boundaryPatch& bp = patches_[patchI];
1771 patches_ = newPatches;
1775 Pout<< "changeFaces : patches now:" << endl;
1777 forAll(patches_, patchI)
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
1790 // Construct face mapping array
1791 oldToNew.setSize(patchIDs.size());
1793 forAll(patchIDs, faceI)
1795 int patchID = patchIDs[faceI];
1797 oldToNew[faceI] = startFace[patchID]++;
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)
1807 newFaces[oldToNew[faceI]] = mesh()[faceI];
1808 newMeshFace[oldToNew[faceI]] = meshFace_[faceI];
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_.
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,
1841 label totalNTris = 0;
1843 nTris.setSize(nFaces);
1845 for (label i = 0; i < nFaces; i++)
1847 label faceNTris = getNTris(startFaceI + i);
1849 nTris[i] = faceNTris;
1851 totalNTris += faceNTris;
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,
1863 const label totalNTris,
1867 // Triangulate faces.
1868 triVerts.setSize(3*totalNTris);
1872 for (label i = 0; i < nFaces; i++)
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()));
1883 f.triangles(mesh().points(), nTri, triFaces);
1885 // Copy into triVerts
1887 forAll(triFaces, triFaceI)
1889 const face& triF = triFaces[triFaceI];
1891 triVerts[vertI++] = triF[0];
1892 triVerts[vertI++] = triF[1];
1893 triVerts[vertI++] = triF[2];
1899 // Number of local points in subset.
1900 Foam::label Foam::boundaryMesh::getNPoints
1902 const label startFaceI,
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,
1919 const label totalNTris,
1920 labelList& triVerts,
1921 labelList& localToGlobal
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);
1936 for (label i = 0; i < nFaces; i++)
1939 const face& f = patch.localFaces()[i];
1941 // Have face triangulate itself (results in faceList)
1942 faceList triFaces(f.nTriangles(patch.localPoints()));
1946 f.triangles(patch.localPoints(), nTri, triFaces);
1948 // Copy into triVerts
1950 forAll(triFaces, triFaceI)
1952 const face& triF = triFaces[triFaceI];
1954 triVerts[vertI++] = triF[0];
1955 triVerts[vertI++] = triF[1];
1956 triVerts[vertI++] = triF[2];
1962 void Foam::boundaryMesh::markFaces
1964 const labelList& protectedEdges,
1965 const label seedFaceI,
1969 boolList protectedEdge(mesh().nEdges(), false);
1971 forAll(protectedEdges, i)
1973 protectedEdge[protectedEdges[i]] = true;
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)
1988 if (currentZone[faceI] == 0)
1990 visited[faceI] = true;
1994 visited[faceI] = false;
2000 // ************************************************************************* //