1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "boundaryMesh.H"
29 #include "repatchPolyTopoChanger.H"
31 #include "indexedOctree.H"
32 #include "treeDataPrimitivePatch.H"
33 #include "triSurface.H"
34 #include "SortableList.H"
36 #include "uindirectPrimitivePatch.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 defineTypeNameAndDebug(Foam::boundaryMesh, 0);
42 // Normal along which to divide faces into categories (used in getNearest)
43 const Foam::vector Foam::boundaryMesh::splitNormal_(3, 2, 1);
45 // Distance to face tolerance for getNearest
46 const Foam::scalar Foam::boundaryMesh::distanceTol_ = 1E-2;
49 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
51 // Returns number of feature edges connected to pointI
52 Foam::label Foam::boundaryMesh::nFeatureEdges(label pointI) const
56 const labelList& pEdges = mesh().pointEdges()[pointI];
58 forAll(pEdges, pEdgeI)
60 label edgeI = pEdges[pEdgeI];
62 if (edgeToFeature_[edgeI] != -1)
71 // Returns next feature edge connected to pointI
72 Foam::label Foam::boundaryMesh::nextFeatureEdge
78 const labelList& pEdges = mesh().pointEdges()[vertI];
80 forAll(pEdges, pEdgeI)
82 label nbrEdgeI = pEdges[pEdgeI];
84 if (nbrEdgeI != edgeI)
86 label featI = edgeToFeature_[nbrEdgeI];
99 // Finds connected feature edges, starting from startPointI and returns
100 // feature labels (not edge labels). Marks feature edges handled in
102 Foam::labelList Foam::boundaryMesh::collectSegment
104 const boolList& isFeaturePoint,
105 const label startEdgeI,
106 boolList& featVisited
109 // Find starting feature point on edge.
111 label edgeI = startEdgeI;
113 const edge& e = mesh().edges()[edgeI];
115 label vertI = e.start();
117 while (!isFeaturePoint[vertI])
119 // Step to next feature edge
121 edgeI = nextFeatureEdge(edgeI, vertI);
123 if ((edgeI == -1) || (edgeI == startEdgeI))
128 // Step to next vertex on edge
130 const edge& e = mesh().edges()[edgeI];
132 vertI = e.otherVertex(vertI);
137 // edgeI : first edge on this segment
138 // vertI : one of the endpoints of this segment
140 // Start walking other way and storing edges as we go along.
143 // Untrimmed storage for current segment
144 labelList featLabels(featureEdges_.size());
146 label featLabelI = 0;
148 label initEdgeI = edgeI;
152 // Mark edge as visited
153 label featI = edgeToFeature_[edgeI];
157 FatalErrorIn("boundaryMesh::collectSegment")
158 << "Problem" << abort(FatalError);
160 featLabels[featLabelI++] = featI;
162 featVisited[featI] = true;
164 // Step to next vertex on edge
166 const edge& e = mesh().edges()[edgeI];
168 vertI = e.otherVertex(vertI);
170 // Step to next feature edge
172 edgeI = nextFeatureEdge(edgeI, vertI);
174 if ((edgeI == -1) || (edgeI == initEdgeI))
179 while (!isFeaturePoint[vertI]);
183 featLabels.setSize(featLabelI);
189 void Foam::boundaryMesh::markEdges
191 const label maxDistance,
193 const label distance,
194 labelList& minDistance,
195 DynamicList<label>& visited
198 if (distance < maxDistance)
200 // Don't do anything if reached beyond maxDistance.
202 if (minDistance[edgeI] == -1)
204 // First visit of edge. Store edge label.
205 visited.append(edgeI);
207 else if (minDistance[edgeI] <= distance)
209 // Already done this edge
213 minDistance[edgeI] = distance;
215 const edge& e = mesh().edges()[edgeI];
217 // Do edges connected to e.start
218 const labelList& startEdges = mesh().pointEdges()[e.start()];
220 forAll(startEdges, pEdgeI)
232 // Do edges connected to e.end
233 const labelList& endEdges = mesh().pointEdges()[e.end()];
235 forAll(endEdges, pEdgeI)
250 Foam::label Foam::boundaryMesh::findPatchID
252 const polyPatchList& patches,
253 const word& patchName
256 forAll(patches, patchI)
258 if (patches[patchI].name() == patchName)
268 Foam::wordList Foam::boundaryMesh::patchNames() const
270 wordList names(patches_.size());
272 forAll(patches_, patchI)
274 names[patchI] = patches_[patchI].name();
280 Foam::label Foam::boundaryMesh::whichPatch
282 const polyPatchList& patches,
286 forAll(patches, patchI)
288 const polyPatch& pp = patches[patchI];
290 if ((faceI >= pp.start()) && (faceI < (pp.start() + pp.size())))
299 // Gets labels of changed faces and propagates them to the edges. Returns
300 // labels of edges changed.
301 Foam::labelList Foam::boundaryMesh::faceToEdge
303 const boolList& regionEdge,
305 const labelList& changedFaces,
306 labelList& edgeRegion
309 labelList changedEdges(mesh().nEdges(), -1);
312 forAll(changedFaces, i)
314 label faceI = changedFaces[i];
316 const labelList& fEdges = mesh().faceEdges()[faceI];
318 forAll(fEdges, fEdgeI)
320 label edgeI = fEdges[fEdgeI];
322 if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
324 edgeRegion[edgeI] = region;
326 changedEdges[changedI++] = edgeI;
331 changedEdges.setSize(changedI);
337 // Reverse of faceToEdge: gets edges and returns faces
338 Foam::labelList Foam::boundaryMesh::edgeToFace
341 const labelList& changedEdges,
342 labelList& faceRegion
345 labelList changedFaces(mesh().size(), -1);
348 forAll(changedEdges, i)
350 label edgeI = changedEdges[i];
352 const labelList& eFaces = mesh().edgeFaces()[edgeI];
354 forAll(eFaces, eFaceI)
356 label faceI = eFaces[eFaceI];
358 if (faceRegion[faceI] == -1)
360 faceRegion[faceI] = region;
362 changedFaces[changedI++] = faceI;
367 changedFaces.setSize(changedI);
373 // Finds area, starting at faceI, delimited by borderEdge
374 void Foam::boundaryMesh::markZone
376 const boolList& borderEdge,
382 faceZone[faceI] = currentZone;
384 // List of faces whose faceZone has been set.
385 labelList changedFaces(1, faceI);
386 // List of edges whose faceZone has been set.
387 labelList changedEdges;
389 // Zones on all edges.
390 labelList edgeZone(mesh().nEdges(), -1);
394 changedEdges = faceToEdge
404 Pout<< "From changedFaces:" << changedFaces.size()
405 << " to changedEdges:" << changedEdges.size()
409 if (changedEdges.empty())
414 changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
418 Pout<< "From changedEdges:" << changedEdges.size()
419 << " to changedFaces:" << changedFaces.size()
423 if (changedFaces.empty())
431 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
434 Foam::boundaryMesh::boundaryMesh()
448 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
450 Foam::boundaryMesh::~boundaryMesh()
456 void Foam::boundaryMesh::clearOut()
467 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
469 void Foam::boundaryMesh::read(const polyMesh& mesh)
473 patches_.setSize(mesh.boundaryMesh().size());
475 // Number of boundary faces
476 label nBFaces = mesh.nFaces() - mesh.nInternalFaces();
478 faceList bFaces(nBFaces);
480 meshFace_.setSize(nBFaces);
484 // Collect all boundary faces.
485 forAll(mesh.boundaryMesh(), patchI)
487 const polyPatch& pp = mesh.boundaryMesh()[patchI];
502 // Collect all faces in global numbering.
503 forAll(pp, patchFaceI)
505 meshFace_[bFaceI] = pp.start() + patchFaceI;
507 bFaces[bFaceI] = pp[patchFaceI];
516 Pout<< "read : patches now:" << endl;
518 forAll(patches_, patchI)
520 const boundaryPatch& bp = patches_[patchI];
522 Pout<< " name : " << bp.name() << endl
523 << " size : " << bp.size() << endl
524 << " start : " << bp.start() << endl
525 << " type : " << bp.physicalType() << endl
531 // Construct single patch for all of boundary
534 // Temporary primitivePatch to calculate compact points & faces.
535 PrimitivePatch<face, List, const pointField&> globalPatch
541 // Store in local(compact) addressing
544 meshPtr_ = new bMesh(globalPatch.localFaces(), globalPatch.localPoints());
549 const bMesh& msh = *meshPtr_;
551 Pout<< "** Start of Faces **" << endl;
555 const face& f = msh[faceI];
557 point ctr(vector::zero);
561 ctr += msh.points()[f[fp]];
571 Pout<< "** End of Faces **" << endl;
573 Pout<< "** Start of Points **" << endl;
575 forAll(msh.points(), pointI)
578 << " coord:" << msh.points()[pointI]
582 Pout<< "** End of Points **" << endl;
585 // Clear edge storage
586 featurePoints_.setSize(0);
587 featureEdges_.setSize(0);
589 featureToEdge_.setSize(0);
590 edgeToFeature_.setSize(meshPtr_->nEdges());
593 featureSegments_.setSize(0);
595 extraEdges_.setSize(0);
599 void Foam::boundaryMesh::readTriSurface(const fileName& fName)
601 triSurface surf(fName);
608 // Sort according to region
609 SortableList<label> regions(surf.size());
613 regions[triI] = surf[triI].region();
617 // Determine region mapping.
618 Map<label> regionToBoundaryPatch;
620 label oldRegion = -1111;
621 label boundPatch = 0;
625 if (regions[i] != oldRegion)
627 regionToBoundaryPatch.insert(regions[i], boundPatch);
629 oldRegion = regions[i];
634 const geometricSurfacePatchList& surfPatches = surf.patches();
638 if (surfPatches.size() == regionToBoundaryPatch.size())
640 // There are as many surface patches as region numbers in triangles
641 // so use the surface patches
643 patches_.setSize(surfPatches.size());
645 // Take over patches, setting size to 0 for now.
646 forAll(surfPatches, patchI)
648 const geometricSurfacePatch& surfPatch = surfPatches[patchI];
659 surfPatch.geometricType()
666 // There are not enough surface patches. Make up my own.
668 patches_.setSize(regionToBoundaryPatch.size());
670 forAll(patches_, patchI)
677 "patch" + name(patchI),
688 // Copy according into bFaces according to regions
691 const labelList& indices = regions.indices();
693 faceList bFaces(surf.size());
695 meshFace_.setSize(surf.size());
699 // Current region number
700 label surfRegion = regions[0];
701 label foamRegion = regionToBoundaryPatch[surfRegion];
703 Pout<< "Surface region " << surfRegion << " becomes boundary patch "
704 << foamRegion << " with name " << patches_[foamRegion].name() << endl;
707 // Index in bFaces of start of current patch
708 label startFaceI = 0;
710 forAll(indices, indexI)
712 label triI = indices[indexI];
714 const labelledTri& tri = surf.localFaces()[triI];
716 if (tri.region() != surfRegion)
718 // Change of region. We now know the size of the previous one.
719 boundaryPatch& bp = patches_[foamRegion];
721 bp.size() = bFaceI - startFaceI;
722 bp.start() = startFaceI;
724 surfRegion = tri.region();
725 foamRegion = regionToBoundaryPatch[surfRegion];
727 Pout<< "Surface region " << surfRegion << " becomes boundary patch "
728 << foamRegion << " with name " << patches_[foamRegion].name()
734 meshFace_[bFaceI] = triI;
736 bFaces[bFaceI++] = face(tri);
740 boundaryPatch& bp = patches_[foamRegion];
742 bp.size() = bFaceI - startFaceI;
743 bp.start() = startFaceI;
746 // Construct single primitivePatch for all of boundary
752 meshPtr_ = new bMesh(bFaces, surf.localPoints());
754 // Clear edge storage
755 featurePoints_.setSize(0);
756 featureEdges_.setSize(0);
758 featureToEdge_.setSize(0);
759 edgeToFeature_.setSize(meshPtr_->nEdges());
762 featureSegments_.setSize(0);
764 extraEdges_.setSize(0);
768 void Foam::boundaryMesh::writeTriSurface(const fileName& fName) const
770 geometricSurfacePatchList surfPatches(patches_.size());
772 forAll(patches_, patchI)
774 const boundaryPatch& bp = patches_[patchI];
776 surfPatches[patchI] =
777 geometricSurfacePatch
786 // Simple triangulation.
789 // Get number of triangles per face
790 labelList nTris(mesh().size());
792 label totalNTris = getNTris(0, mesh().size(), nTris);
794 // Determine per face the starting triangle.
795 labelList startTri(mesh().size());
799 forAll(mesh(), faceI)
801 startTri[faceI] = triI;
803 triI += nTris[faceI];
807 labelList triVerts(3*totalNTris);
809 triangulate(0, mesh().size(), totalNTris, triVerts);
811 // Convert to labelledTri
813 List<labelledTri> tris(totalNTris);
817 forAll(patches_, patchI)
819 const boundaryPatch& bp = patches_[patchI];
821 forAll(bp, patchFaceI)
823 label faceI = bp.start() + patchFaceI;
825 label triVertI = 3*startTri[faceI];
827 for (label faceTriI = 0; faceTriI < nTris[faceI]; faceTriI++)
829 label v0 = triVerts[triVertI++];
830 label v1 = triVerts[triVertI++];
831 label v2 = triVerts[triVertI++];
833 tris[triI++] = labelledTri(v0, v1, v2, patchI);
838 triSurface surf(tris, surfPatches, mesh().points());
840 OFstream surfStream(fName);
842 surf.write(surfStream);
846 // Get index in this (boundaryMesh) of face nearest to each boundary face in
848 // Origininally all triangles/faces of boundaryMesh would be bunged into
849 // one big octree. Problem was that faces on top of each other, differing
850 // only in sign of normal, could not be found separately. It would always
851 // find only one. We could detect that it was probably finding the wrong one
852 // (based on normal) but could not 'tell' the octree to retrieve the other
853 // one (since they occupy exactly the same space)
854 // So now faces get put into different octrees depending on normal.
855 // !It still will not be possible to differentiate between two faces on top
856 // of each other having the same normal
857 Foam::labelList Foam::boundaryMesh::getNearest
859 const primitiveMesh& pMesh,
860 const vector& searchSpan
864 // Divide faces into two bins acc. to normal
865 // - left of splitNormal
867 DynamicList<label> leftFaces(mesh().size()/2);
868 DynamicList<label> rightFaces(mesh().size()/2);
870 forAll(mesh(), bFaceI)
872 scalar sign = mesh().faceNormals()[bFaceI] & splitNormal_;
876 rightFaces.append(bFaceI);
880 leftFaces.append(bFaceI);
889 Pout<< "getNearest :"
890 << " rightBin:" << rightFaces.size()
891 << " leftBin:" << leftFaces.size()
895 uindirectPrimitivePatch leftPatch
897 UIndirectList<face>(mesh(), leftFaces),
900 uindirectPrimitivePatch rightPatch
902 UIndirectList<face>(mesh(), rightFaces),
908 treeBoundBox overallBb(mesh().localPoints());
910 // Extend domain slightly (also makes it 3D if was 2D)
911 // Note asymmetry to avoid having faces align with octree cubes.
912 scalar tol = 1E-6 * overallBb.avgDim();
914 point& bbMin = overallBb.min();
919 point& bbMax = overallBb.max();
924 // Create the octrees
927 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
930 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
942 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
945 treeDataPrimitivePatch<face, UIndirectList, const pointField&>
958 Pout<< "getNearest : built trees" << endl;
962 const vectorField& ns = mesh().faceNormals();
966 // Search nearest triangle centre for every polyMesh boundary face
969 labelList nearestBFaceI(pMesh.nFaces() - pMesh.nInternalFaces());
971 treeBoundBox tightest;
973 const scalar searchDimSqr = magSqr(searchSpan);
975 forAll(nearestBFaceI, patchFaceI)
977 label meshFaceI = pMesh.nInternalFaces() + patchFaceI;
979 const point& ctr = pMesh.faceCentres()[meshFaceI];
981 if (debug && (patchFaceI % 1000) == 0)
983 Pout<< "getNearest : patchFace:" << patchFaceI
984 << " meshFaceI:" << meshFaceI << " ctr:" << ctr << endl;
988 // Get normal from area vector
989 vector n = pMesh.faceAreas()[meshFaceI];
990 scalar area = mag(n);
993 scalar typDim = -GREAT;
994 const face& f = pMesh.faces()[meshFaceI];
998 typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
1001 // Search right tree
1002 pointIndexHit rightInfo = rightTree.findNearest(ctr, searchDimSqr);
1004 // Search left tree. Note: could start from rightDist bounding box
1005 // instead of starting from top.
1006 pointIndexHit leftInfo = leftTree.findNearest(ctr, searchDimSqr);
1008 if (rightInfo.hit())
1012 // Found in both trees. Compare normals.
1013 label rightFaceI = rightFaces[rightInfo.index()];
1014 label leftFaceI = leftFaces[leftInfo.index()];
1016 label rightDist = mag(rightInfo.hitPoint()-ctr);
1017 label leftDist = mag(leftInfo.hitPoint()-ctr);
1019 scalar rightSign = n & ns[rightFaceI];
1020 scalar leftSign = n & ns[leftFaceI];
1024 (rightSign > 0 && leftSign > 0)
1025 || (rightSign < 0 && leftSign < 0)
1028 // Both same sign. Choose nearest.
1029 if (rightDist < leftDist)
1031 nearestBFaceI[patchFaceI] = rightFaceI;
1035 nearestBFaceI[patchFaceI] = leftFaceI;
1041 // - if both near enough choose one with correct sign
1042 // - otherwise choose nearest.
1044 // Get local dimension as max of distance between ctr and
1047 typDim *= distanceTol_;
1049 if (rightDist < typDim && leftDist < typDim)
1051 // Different sign and nearby. Choosing matching normal
1054 nearestBFaceI[patchFaceI] = rightFaceI;
1058 nearestBFaceI[patchFaceI] = leftFaceI;
1063 // Different sign but faraway. Choosing nearest.
1064 if (rightDist < leftDist)
1066 nearestBFaceI[patchFaceI] = rightFaceI;
1070 nearestBFaceI[patchFaceI] = leftFaceI;
1077 // Found in right but not in left. Choose right regardless if
1078 // correct sign. Note: do we want this?
1079 label rightFaceI = rightFaces[rightInfo.index()];
1080 nearestBFaceI[patchFaceI] = rightFaceI;
1085 // No face found in right tree.
1089 // Found in left but not in right. Choose left regardless if
1090 // correct sign. Note: do we want this?
1091 nearestBFaceI[patchFaceI] = leftFaces[leftInfo.index()];
1095 // No face found in left tree.
1096 nearestBFaceI[patchFaceI] = -1;
1101 return nearestBFaceI;
1105 void Foam::boundaryMesh::patchify
1107 const labelList& nearest,
1108 const polyBoundaryMesh& oldPatches,
1113 // 2 cases to be handled:
1114 // A- patches in boundaryMesh patches_
1115 // B- patches not in boundaryMesh patches_ but in polyMesh
1117 // Create maps from patch name to new patch index.
1118 HashTable<label> nameToIndex(2*patches_.size());
1120 Map<word> indexToName(2*patches_.size());
1123 label nNewPatches = patches_.size();
1125 forAll(oldPatches, oldPatchI)
1127 const polyPatch& patch = oldPatches[oldPatchI];
1128 const label newPatchI = findPatchID(patch.name());
1130 if (newPatchI != -1)
1132 nameToIndex.insert(patch.name(), newPatchI);
1133 indexToName.insert(newPatchI, patch.name());
1137 // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1139 forAll(patches_, bPatchI)
1141 const boundaryPatch& bp = patches_[bPatchI];
1143 if (!nameToIndex.found(bp.name()))
1145 nameToIndex.insert(bp.name(), bPatchI);
1146 indexToName.insert(bPatchI, bp.name());
1151 // Copy names&type of patches (with zero size) from old mesh as far as
1152 // possible. First patch created gets all boundary faces; all others get
1153 // zero faces (repatched later on). Exception is coupled patches which
1156 List<polyPatch*> newPatchPtrList(nNewPatches);
1158 label meshFaceI = newMesh.nInternalFaces();
1160 // First patch gets all non-coupled faces
1161 label facesToBeDone = newMesh.nFaces() - newMesh.nInternalFaces();
1163 forAll(patches_, bPatchI)
1165 const boundaryPatch& bp = patches_[bPatchI];
1167 const label newPatchI = nameToIndex[bp.name()];
1169 // Find corresponding patch in polyMesh
1170 const label oldPatchI = findPatchID(oldPatches, bp.name());
1172 if (oldPatchI == -1)
1174 // Newly created patch. Gets all or zero faces.
1177 Pout<< "patchify : Creating new polyPatch:" << bp.name()
1178 << " type:" << bp.physicalType() << endl;
1181 newPatchPtrList[newPatchI] = polyPatch::New
1188 newMesh.boundaryMesh()
1191 meshFaceI += facesToBeDone;
1193 // first patch gets all boundary faces; all others get 0.
1198 // Existing patch. Gets all or zero faces.
1199 const polyPatch& oldPatch = oldPatches[oldPatchI];
1203 Pout<< "patchify : Cloning existing polyPatch:"
1204 << oldPatch.name() << endl;
1207 newPatchPtrList[newPatchI] = oldPatch.clone
1209 newMesh.boundaryMesh(),
1215 meshFaceI += facesToBeDone;
1217 // first patch gets all boundary faces; all others get 0.
1225 Pout<< "Patchify : new polyPatch list:" << endl;
1227 forAll(newPatchPtrList, patchI)
1229 const polyPatch& newPatch = *newPatchPtrList[patchI];
1233 Pout<< "polyPatch:" << newPatch.name() << endl
1234 << " type :" << newPatch.typeName << endl
1235 << " size :" << newPatch.size() << endl
1236 << " start:" << newPatch.start() << endl
1237 << " index:" << patchI << endl;
1242 // Actually add new list of patches
1243 repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1244 polyMeshRepatcher.changePatches(newPatchPtrList);
1248 // Change patch type for face
1250 if (newPatchPtrList.size())
1252 List<DynamicList<label> > patchFaces(nNewPatches);
1254 // Give reasonable estimate for size of patches
1256 (newMesh.nFaces() - newMesh.nInternalFaces())
1259 forAll(patchFaces, newPatchI)
1261 patchFaces[newPatchI].setCapacity(nAvgFaces);
1265 // Sort faces acc. to new patch index. Can loop over all old patches
1266 // since will contain all faces.
1269 forAll(oldPatches, oldPatchI)
1271 const polyPatch& patch = oldPatches[oldPatchI];
1273 forAll(patch, patchFaceI)
1275 // Put face into region given by nearest boundary face
1277 label meshFaceI = patch.start() + patchFaceI;
1279 label bFaceI = meshFaceI - newMesh.nInternalFaces();
1281 patchFaces[whichPatch(nearest[bFaceI])].append(meshFaceI);
1285 forAll(patchFaces, newPatchI)
1287 patchFaces[newPatchI].shrink();
1291 // Change patch > 0. (since above we put all faces into the zeroth
1294 for (label newPatchI = 1; newPatchI < patchFaces.size(); newPatchI++)
1296 const labelList& pFaces = patchFaces[newPatchI];
1298 forAll(pFaces, pFaceI)
1300 polyMeshRepatcher.changePatchID(pFaces[pFaceI], newPatchI);
1304 polyMeshRepatcher.repatch();
1309 void Foam::boundaryMesh::setFeatureEdges(const scalar minCos)
1311 edgeToFeature_.setSize(mesh().nEdges());
1313 edgeToFeature_ = -1;
1315 // 1. Mark feature edges
1317 // Storage for edge labels that are features. Trim later.
1318 featureToEdge_.setSize(mesh().nEdges());
1322 if (minCos >= 0.9999)
1324 // Select everything
1325 forAll(mesh().edges(), edgeI)
1327 edgeToFeature_[edgeI] = featureI;
1328 featureToEdge_[featureI++] = edgeI;
1333 forAll(mesh().edges(), edgeI)
1335 const labelList& eFaces = mesh().edgeFaces()[edgeI];
1337 if (eFaces.size() == 2)
1339 label face0I = eFaces[0];
1341 label face1I = eFaces[1];
1343 ////- Uncomment below code if you want to include patch
1344 //// boundaries in feature edges.
1345 //if (whichPatch(face0I) != whichPatch(face1I))
1347 // edgeToFeature_[edgeI] = featureI;
1348 // featureToEdge_[featureI++] = edgeI;
1352 const vector& n0 = mesh().faceNormals()[face0I];
1354 const vector& n1 = mesh().faceNormals()[face1I];
1356 float cosAng = n0 & n1;
1358 if (cosAng < minCos)
1360 edgeToFeature_[edgeI] = featureI;
1361 featureToEdge_[featureI++] = edgeI;
1367 //Should not occur: 0 or more than two faces
1368 edgeToFeature_[edgeI] = featureI;
1369 featureToEdge_[featureI++] = edgeI;
1374 // Trim featureToEdge_ to actual number of edges.
1375 featureToEdge_.setSize(featureI);
1378 // Compact edges i.e. relabel vertices.
1381 featureEdges_.setSize(featureI);
1382 featurePoints_.setSize(mesh().nPoints());
1384 labelList featToMeshPoint(mesh().nPoints(), -1);
1388 forAll(featureToEdge_, fEdgeI)
1390 label edgeI = featureToEdge_[fEdgeI];
1392 const edge& e = mesh().edges()[edgeI];
1394 label start = featToMeshPoint[e.start()];
1398 featToMeshPoint[e.start()] = featPtI;
1400 featurePoints_[featPtI] = mesh().points()[e.start()];
1407 label end = featToMeshPoint[e.end()];
1411 featToMeshPoint[e.end()] = featPtI;
1413 featurePoints_[featPtI] = mesh().points()[e.end()];
1420 // Store with renumbered vertices.
1421 featureEdges_[fEdgeI] = edge(start, end);
1425 featurePoints_.setSize(featPtI);
1429 // 2. Mark endpoints of feature segments. These are points with
1430 // != 2 feature edges connected.
1431 // Note: can add geometric constraint here as well that if 2 feature
1432 // edges the angle between them should be less than xxx.
1435 boolList isFeaturePoint(mesh().nPoints(), false);
1437 forAll(featureToEdge_, featI)
1439 label edgeI = featureToEdge_[featI];
1441 const edge& e = mesh().edges()[edgeI];
1443 if (nFeatureEdges(e.start()) != 2)
1445 isFeaturePoint[e.start()] = true;
1448 if (nFeatureEdges(e.end()) != 2)
1450 isFeaturePoint[e.end()] = true;
1456 // 3: Split feature edges into segments:
1457 // find point with not 2 feature edges -> start of feature segment
1460 DynamicList<labelList> segments;
1463 boolList featVisited(featureToEdge_.size(), false);
1467 label startFeatI = -1;
1469 forAll(featVisited, featI)
1471 if (!featVisited[featI])
1479 if (startFeatI == -1)
1481 // No feature lines left.
1490 featureToEdge_[startFeatI],
1501 featureSegments_.setSize(segments.size());
1503 forAll(featureSegments_, segmentI)
1505 featureSegments_[segmentI] = segments[segmentI];
1510 void Foam::boundaryMesh::setExtraEdges(const label edgeI)
1512 labelList minDistance(mesh().nEdges(), -1);
1514 // All edge labels encountered
1515 DynamicList<label> visitedEdges;
1517 // Floodfill from edgeI starting from distance 0. Stop at distance.
1518 markEdges(8, edgeI, 0, minDistance, visitedEdges);
1520 // Set edge labels to display
1521 extraEdges_.transfer(visitedEdges);
1525 Foam::label Foam::boundaryMesh::whichPatch(const label faceI) const
1527 forAll(patches_, patchI)
1529 const boundaryPatch& bp = patches_[patchI];
1531 if ((faceI >= bp.start()) && (faceI < (bp.start() + bp.size())))
1537 FatalErrorIn("boundaryMesh::whichPatch(const label)")
1538 << "Cannot find face " << faceI << " in list of boundaryPatches "
1540 << abort(FatalError);
1546 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1548 forAll(patches_, patchI)
1550 if (patches_[patchI].name() == patchName)
1560 void Foam::boundaryMesh::addPatch(const word& patchName)
1562 patches_.setSize(patches_.size() + 1);
1564 // Add empty patch at end of patch list.
1566 label patchI = patches_.size()-1;
1568 boundaryPatch* bpPtr = new boundaryPatch
1577 patches_.set(patchI, bpPtr);
1581 Pout<< "addPatch : patches now:" << endl;
1583 forAll(patches_, patchI)
1585 const boundaryPatch& bp = patches_[patchI];
1587 Pout<< " name : " << bp.name() << endl
1588 << " size : " << bp.size() << endl
1589 << " start : " << bp.start() << endl
1590 << " type : " << bp.physicalType() << endl
1597 void Foam::boundaryMesh::deletePatch(const word& patchName)
1599 const label delPatchI = findPatchID(patchName);
1601 if (delPatchI == -1)
1603 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1604 << "Can't find patch named " << patchName
1605 << abort(FatalError);
1608 if (patches_[delPatchI].size())
1610 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1611 << "Trying to delete non-empty patch " << patchName
1612 << endl << "Current size:" << patches_[delPatchI].size()
1613 << abort(FatalError);
1616 PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1618 for (label patchI = 0; patchI < delPatchI; patchI++)
1620 newPatches.set(patchI, patches_[patchI].clone());
1623 // Move patches down, starting from delPatchI.
1625 for (label patchI = delPatchI + 1; patchI < patches_.size(); patchI++)
1627 newPatches.set(patchI - 1, patches_[patchI].clone());
1632 patches_ = newPatches;
1636 Pout<< "deletePatch : patches now:" << endl;
1638 forAll(patches_, patchI)
1640 const boundaryPatch& bp = patches_[patchI];
1642 Pout<< " name : " << bp.name() << endl
1643 << " size : " << bp.size() << endl
1644 << " start : " << bp.start() << endl
1645 << " type : " << bp.physicalType() << endl
1652 void Foam::boundaryMesh::changePatchType
1654 const word& patchName,
1655 const word& patchType
1658 const label changeI = findPatchID(patchName);
1662 FatalErrorIn("boundaryMesh::changePatchType(const word&, const word&)")
1663 << "Can't find patch named " << patchName
1664 << abort(FatalError);
1668 // Cause we can't reassign to individual PtrList elems ;-(
1672 PtrList<boundaryPatch> newPatches(patches_.size());
1674 forAll(patches_, patchI)
1676 if (patchI == changeI)
1678 // Create copy but for type
1679 const boundaryPatch& oldBp = patches_[patchI];
1681 boundaryPatch* bpPtr = new boundaryPatch
1690 newPatches.set(patchI, bpPtr);
1695 newPatches.set(patchI, patches_[patchI].clone());
1699 patches_ = newPatches;
1703 void Foam::boundaryMesh::changeFaces
1705 const labelList& patchIDs,
1709 if (patchIDs.size() != mesh().size())
1711 FatalErrorIn("boundaryMesh::changeFaces(const labelList& patchIDs)")
1712 << "List of patchIDs not equal to number of faces." << endl
1713 << "PatchIDs size:" << patchIDs.size()
1714 << " nFaces::" << mesh().size()
1715 << abort(FatalError);
1718 // Count number of faces for each patch
1720 labelList nFaces(patches_.size(), 0);
1722 forAll(patchIDs, faceI)
1724 label patchID = patchIDs[faceI];
1726 if (patchID < 0 || patchID >= patches_.size())
1728 FatalErrorIn("boundaryMesh::changeFaces(const labelList&)")
1729 << "PatchID " << patchID << " out of range"
1730 << abort(FatalError);
1736 // Determine position in faces_ for each patch
1738 labelList startFace(patches_.size());
1742 for (label patchI = 1; patchI < patches_.size(); patchI++)
1744 startFace[patchI] = startFace[patchI-1] + nFaces[patchI-1];
1747 // Update patch info
1748 PtrList<boundaryPatch> newPatches(patches_.size());
1750 forAll(patches_, patchI)
1752 const boundaryPatch& bp = patches_[patchI];
1767 patches_ = newPatches;
1771 Pout<< "changeFaces : patches now:" << endl;
1773 forAll(patches_, patchI)
1775 const boundaryPatch& bp = patches_[patchI];
1777 Pout<< " name : " << bp.name() << endl
1778 << " size : " << bp.size() << endl
1779 << " start : " << bp.start() << endl
1780 << " type : " << bp.physicalType() << endl
1786 // Construct face mapping array
1787 oldToNew.setSize(patchIDs.size());
1789 forAll(patchIDs, faceI)
1791 int patchID = patchIDs[faceI];
1793 oldToNew[faceI] = startFace[patchID]++;
1796 // Copy faces into correct position and maintain label of original face
1797 faceList newFaces(mesh().size());
1799 labelList newMeshFace(mesh().size());
1801 forAll(oldToNew, faceI)
1803 newFaces[oldToNew[faceI]] = mesh()[faceI];
1804 newMeshFace[oldToNew[faceI]] = meshFace_[faceI];
1807 // Reconstruct 'mesh' from new faces and (copy of) existing points.
1808 bMesh* newMeshPtr_ = new bMesh(newFaces, mesh().points());
1810 // Reset meshFace_ to new ordering.
1811 meshFace_.transfer(newMeshFace);
1814 // Remove old PrimitivePatch on meshPtr_.
1817 // And insert new 'mesh'.
1818 meshPtr_ = newMeshPtr_;
1822 Foam::label Foam::boundaryMesh::getNTris(const label faceI) const
1824 const face& f = mesh()[faceI];
1826 return f.nTriangles(mesh().points());
1830 Foam::label Foam::boundaryMesh::getNTris
1832 const label startFaceI,
1837 label totalNTris = 0;
1839 nTris.setSize(nFaces);
1841 for (label i = 0; i < nFaces; i++)
1843 label faceNTris = getNTris(startFaceI + i);
1845 nTris[i] = faceNTris;
1847 totalNTris += faceNTris;
1853 // Simple triangulation of face subset. Stores vertices in tris[] as three
1854 // consecutive vertices per triangle.
1855 void Foam::boundaryMesh::triangulate
1857 const label startFaceI,
1859 const label totalNTris,
1863 // Triangulate faces.
1864 triVerts.setSize(3*totalNTris);
1868 for (label i = 0; i < nFaces; i++)
1870 label faceI = startFaceI + i;
1872 const face& f = mesh()[faceI];
1874 // Have face triangulate itself (results in faceList)
1875 faceList triFaces(f.nTriangles(mesh().points()));
1879 f.triangles(mesh().points(), nTri, triFaces);
1881 // Copy into triVerts
1883 forAll(triFaces, triFaceI)
1885 const face& triF = triFaces[triFaceI];
1887 triVerts[vertI++] = triF[0];
1888 triVerts[vertI++] = triF[1];
1889 triVerts[vertI++] = triF[2];
1895 // Number of local points in subset.
1896 Foam::label Foam::boundaryMesh::getNPoints
1898 const label startFaceI,
1902 SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1904 primitivePatch patch(patchFaces, mesh().points());
1906 return patch.nPoints();
1910 // Triangulation of face subset in local coords.
1911 void Foam::boundaryMesh::triangulateLocal
1913 const label startFaceI,
1915 const label totalNTris,
1916 labelList& triVerts,
1917 labelList& localToGlobal
1920 SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1922 primitivePatch patch(patchFaces, mesh().points());
1924 // Map from local to mesh().points() addressing
1925 localToGlobal = patch.meshPoints();
1927 // Triangulate patch faces.
1928 triVerts.setSize(3*totalNTris);
1932 for (label i = 0; i < nFaces; i++)
1935 const face& f = patch.localFaces()[i];
1937 // Have face triangulate itself (results in faceList)
1938 faceList triFaces(f.nTriangles(patch.localPoints()));
1942 f.triangles(patch.localPoints(), nTri, triFaces);
1944 // Copy into triVerts
1946 forAll(triFaces, triFaceI)
1948 const face& triF = triFaces[triFaceI];
1950 triVerts[vertI++] = triF[0];
1951 triVerts[vertI++] = triF[1];
1952 triVerts[vertI++] = triF[2];
1958 void Foam::boundaryMesh::markFaces
1960 const labelList& protectedEdges,
1961 const label seedFaceI,
1965 boolList protectedEdge(mesh().nEdges(), false);
1967 forAll(protectedEdges, i)
1969 protectedEdge[protectedEdges[i]] = true;
1973 // Initialize zone for all faces to -1
1974 labelList currentZone(mesh().size(), -1);
1976 // Mark with 0 all faces reachable from seedFaceI
1977 markZone(protectedEdge, seedFaceI, 0, currentZone);
1979 // Set in visited all reached ones.
1980 visited.setSize(mesh().size());
1982 forAll(currentZone, faceI)
1984 if (currentZone[faceI] == 0)
1986 visited[faceI] = true;
1990 visited[faceI] = false;
1996 // ************************************************************************* //