1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
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"
32 #include "octreeDataFaceList.H"
33 #include "triSurface.H"
34 #include "SortableList.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(Foam::boundaryMesh, 0);
41 // Normal along which to divide faces into categories (used in getNearest)
42 const Foam::vector Foam::boundaryMesh::splitNormal_(3, 2, 1);
44 // Distance to face tolerance for getNearest
45 const Foam::scalar Foam::boundaryMesh::distanceTol_ = 1E-2;
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 // Returns number of feature edges connected to pointI
51 Foam::label Foam::boundaryMesh::nFeatureEdges(label pointI) const
55 const labelList& pEdges = mesh().pointEdges()[pointI];
57 forAll(pEdges, pEdgeI)
59 label edgeI = pEdges[pEdgeI];
61 if (edgeToFeature_[edgeI] != -1)
70 // Returns next feature edge connected to pointI
71 Foam::label Foam::boundaryMesh::nextFeatureEdge
77 const labelList& pEdges = mesh().pointEdges()[vertI];
79 forAll(pEdges, pEdgeI)
81 label nbrEdgeI = pEdges[pEdgeI];
83 if (nbrEdgeI != edgeI)
85 label featI = edgeToFeature_[nbrEdgeI];
98 // Finds connected feature edges, starting from startPointI and returns
99 // feature labels (not edge labels). Marks feature edges handled in
101 Foam::labelList Foam::boundaryMesh::collectSegment
103 const boolList& isFeaturePoint,
104 const label startEdgeI,
105 boolList& featVisited
108 // Find starting feature point on edge.
110 label edgeI = startEdgeI;
112 const edge& e = mesh().edges()[edgeI];
114 label vertI = e.start();
116 while (!isFeaturePoint[vertI])
118 // Step to next feature edge
120 edgeI = nextFeatureEdge(edgeI, vertI);
122 if ((edgeI == -1) || (edgeI == startEdgeI))
127 // Step to next vertex on edge
129 const edge& e = mesh().edges()[edgeI];
131 vertI = e.otherVertex(vertI);
136 // edgeI : first edge on this segment
137 // vertI : one of the endpoints of this segment
139 // Start walking other way and storing edges as we go along.
142 // Untrimmed storage for current segment
143 labelList featLabels(featureEdges_.size());
145 label featLabelI = 0;
147 label initEdgeI = edgeI;
151 // Mark edge as visited
152 label featI = edgeToFeature_[edgeI];
156 FatalErrorIn("boundaryMesh::collectSegment")
157 << "Problem" << abort(FatalError);
159 featLabels[featLabelI++] = featI;
161 featVisited[featI] = true;
163 // Step to next vertex on edge
165 const edge& e = mesh().edges()[edgeI];
167 vertI = e.otherVertex(vertI);
169 // Step to next feature edge
171 edgeI = nextFeatureEdge(edgeI, vertI);
173 if ((edgeI == -1) || (edgeI == initEdgeI))
178 while (!isFeaturePoint[vertI]);
182 featLabels.setSize(featLabelI);
188 void Foam::boundaryMesh::markEdges
190 const label maxDistance,
192 const label distance,
193 labelList& minDistance,
194 DynamicList<label>& visited
197 if (distance < maxDistance)
199 // Don't do anything if reached beyond maxDistance.
201 if (minDistance[edgeI] == -1)
203 // First visit of edge. Store edge label.
204 visited.append(edgeI);
206 else if (minDistance[edgeI] <= distance)
208 // Already done this edge
212 minDistance[edgeI] = distance;
214 const edge& e = mesh().edges()[edgeI];
216 // Do edges connected to e.start
217 const labelList& startEdges = mesh().pointEdges()[e.start()];
219 forAll(startEdges, pEdgeI)
231 // Do edges connected to e.end
232 const labelList& endEdges = mesh().pointEdges()[e.end()];
234 forAll(endEdges, pEdgeI)
249 Foam::label Foam::boundaryMesh::findPatchID
251 const polyPatchList& patches,
252 const word& patchName
255 forAll(patches, patchI)
257 if (patches[patchI].name() == patchName)
267 Foam::wordList Foam::boundaryMesh::patchNames() const
269 wordList names(patches_.size());
271 forAll(patches_, patchI)
273 names[patchI] = patches_[patchI].name();
279 Foam::label Foam::boundaryMesh::whichPatch
281 const polyPatchList& patches,
285 forAll(patches, patchI)
287 const polyPatch& pp = patches[patchI];
289 if ((faceI >= pp.start()) && (faceI < (pp.start() + pp.size())))
298 // Gets labels of changed faces and propagates them to the edges. Returns
299 // labels of edges changed.
300 Foam::labelList Foam::boundaryMesh::faceToEdge
302 const boolList& regionEdge,
304 const labelList& changedFaces,
305 labelList& edgeRegion
308 labelList changedEdges(mesh().nEdges(), -1);
311 forAll(changedFaces, i)
313 label faceI = changedFaces[i];
315 const labelList& fEdges = mesh().faceEdges()[faceI];
317 forAll(fEdges, fEdgeI)
319 label edgeI = fEdges[fEdgeI];
321 if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
323 edgeRegion[edgeI] = region;
325 changedEdges[changedI++] = edgeI;
330 changedEdges.setSize(changedI);
336 // Reverse of faceToEdge: gets edges and returns faces
337 Foam::labelList Foam::boundaryMesh::edgeToFace
340 const labelList& changedEdges,
341 labelList& faceRegion
344 labelList changedFaces(mesh().size(), -1);
347 forAll(changedEdges, i)
349 label edgeI = changedEdges[i];
351 const labelList& eFaces = mesh().edgeFaces()[edgeI];
353 forAll(eFaces, eFaceI)
355 label faceI = eFaces[eFaceI];
357 if (faceRegion[faceI] == -1)
359 faceRegion[faceI] = region;
361 changedFaces[changedI++] = faceI;
366 changedFaces.setSize(changedI);
372 // Finds area, starting at faceI, delimited by borderEdge
373 void Foam::boundaryMesh::markZone
375 const boolList& borderEdge,
381 faceZone[faceI] = currentZone;
383 // List of faces whose faceZone has been set.
384 labelList changedFaces(1, faceI);
385 // List of edges whose faceZone has been set.
386 labelList changedEdges;
388 // Zones on all edges.
389 labelList edgeZone(mesh().nEdges(), -1);
393 changedEdges = faceToEdge
403 Pout<< "From changedFaces:" << changedFaces.size()
404 << " to changedEdges:" << changedEdges.size()
408 if (changedEdges.empty())
413 changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
417 Pout<< "From changedEdges:" << changedEdges.size()
418 << " to changedFaces:" << changedFaces.size()
422 if (changedFaces.empty())
430 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
433 Foam::boundaryMesh::boundaryMesh()
447 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
449 Foam::boundaryMesh::~boundaryMesh()
455 void Foam::boundaryMesh::clearOut()
466 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
468 void Foam::boundaryMesh::read(const polyMesh& mesh)
472 patches_.setSize(mesh.boundaryMesh().size());
474 // Number of boundary faces
475 label nBFaces = mesh.nFaces() - mesh.nInternalFaces();
477 faceList bFaces(nBFaces);
479 meshFace_.setSize(nBFaces);
483 // Collect all boundary faces.
484 forAll(mesh.boundaryMesh(), patchI)
486 const polyPatch& pp = mesh.boundaryMesh()[patchI];
501 // Collect all faces in global numbering.
502 forAll(pp, patchFaceI)
504 meshFace_[bFaceI] = pp.start() + patchFaceI;
506 bFaces[bFaceI] = pp[patchFaceI];
515 Pout<< "read : patches now:" << endl;
517 forAll(patches_, patchI)
519 const boundaryPatch& bp = patches_[patchI];
521 Pout<< " name : " << bp.name() << endl
522 << " size : " << bp.size() << endl
523 << " start : " << bp.start() << endl
524 << " type : " << bp.physicalType() << endl
530 // Construct single patch for all of boundary
533 // Temporary primitivePatch to calculate compact points & faces.
534 PrimitivePatch<face, List, const pointField&> globalPatch
540 // Store in local(compact) addressing
543 meshPtr_ = new bMesh(globalPatch.localFaces(), globalPatch.localPoints());
548 const bMesh& msh = *meshPtr_;
550 Pout<< "** Start of Faces **" << endl;
554 const face& f = msh[faceI];
556 point ctr(vector::zero);
560 ctr += msh.points()[f[fp]];
570 Pout<< "** End of Faces **" << endl;
572 Pout<< "** Start of Points **" << endl;
574 forAll(msh.points(), pointI)
577 << " coord:" << msh.points()[pointI]
581 Pout<< "** End of Points **" << endl;
584 // Clear edge storage
585 featurePoints_.setSize(0);
586 featureEdges_.setSize(0);
588 featureToEdge_.setSize(0);
589 edgeToFeature_.setSize(meshPtr_->nEdges());
592 featureSegments_.setSize(0);
594 extraEdges_.setSize(0);
598 void Foam::boundaryMesh::readTriSurface(const fileName& fName)
600 triSurface surf(fName);
607 // Sort according to region
608 SortableList<label> regions(surf.size());
612 regions[triI] = surf[triI].region();
616 // Determine region mapping.
617 Map<label> regionToBoundaryPatch;
619 label oldRegion = -1111;
620 label boundPatch = 0;
624 if (regions[i] != oldRegion)
626 regionToBoundaryPatch.insert(regions[i], boundPatch);
628 oldRegion = regions[i];
633 const geometricSurfacePatchList& surfPatches = surf.patches();
637 if (surfPatches.size() == regionToBoundaryPatch.size())
639 // There are as many surface patches as region numbers in triangles
640 // so use the surface patches
642 patches_.setSize(surfPatches.size());
644 // Take over patches, setting size to 0 for now.
645 forAll(surfPatches, patchI)
647 const geometricSurfacePatch& surfPatch = surfPatches[patchI];
658 surfPatch.geometricType()
665 // There are not enough surface patches. Make up my own.
667 patches_.setSize(regionToBoundaryPatch.size());
669 forAll(patches_, patchI)
676 "patch" + name(patchI),
687 // Copy according into bFaces according to regions
690 const labelList& indices = regions.indices();
692 faceList bFaces(surf.size());
694 meshFace_.setSize(surf.size());
698 // Current region number
699 label surfRegion = regions[0];
700 label foamRegion = regionToBoundaryPatch[surfRegion];
702 Pout<< "Surface region " << surfRegion << " becomes boundary patch "
703 << foamRegion << " with name " << patches_[foamRegion].name() << endl;
706 // Index in bFaces of start of current patch
707 label startFaceI = 0;
709 forAll(indices, indexI)
711 label triI = indices[indexI];
713 const labelledTri& tri = surf.localFaces()[triI];
715 if (tri.region() != surfRegion)
717 // Change of region. We now know the size of the previous one.
718 boundaryPatch& bp = patches_[foamRegion];
720 bp.size() = bFaceI - startFaceI;
721 bp.start() = startFaceI;
723 surfRegion = tri.region();
724 foamRegion = regionToBoundaryPatch[surfRegion];
726 Pout<< "Surface region " << surfRegion << " becomes boundary patch "
727 << foamRegion << " with name " << patches_[foamRegion].name()
733 meshFace_[bFaceI] = triI;
735 bFaces[bFaceI++] = face(tri);
739 boundaryPatch& bp = patches_[foamRegion];
741 bp.size() = bFaceI - startFaceI;
742 bp.start() = startFaceI;
745 // Construct single primitivePatch for all of boundary
751 meshPtr_ = new bMesh(bFaces, surf.localPoints());
753 // Clear edge storage
754 featurePoints_.setSize(0);
755 featureEdges_.setSize(0);
757 featureToEdge_.setSize(0);
758 edgeToFeature_.setSize(meshPtr_->nEdges());
761 featureSegments_.setSize(0);
763 extraEdges_.setSize(0);
767 void Foam::boundaryMesh::writeTriSurface(const fileName& fName) const
769 geometricSurfacePatchList surfPatches(patches_.size());
771 forAll(patches_, patchI)
773 const boundaryPatch& bp = patches_[patchI];
775 surfPatches[patchI] =
776 geometricSurfacePatch
785 // Simple triangulation.
788 // Get number of triangles per face
789 labelList nTris(mesh().size());
791 label totalNTris = getNTris(0, mesh().size(), nTris);
793 // Determine per face the starting triangle.
794 labelList startTri(mesh().size());
798 forAll(mesh(), faceI)
800 startTri[faceI] = triI;
802 triI += nTris[faceI];
806 labelList triVerts(3*totalNTris);
808 triangulate(0, mesh().size(), totalNTris, triVerts);
810 // Convert to labelledTri
812 List<labelledTri> tris(totalNTris);
816 forAll(patches_, patchI)
818 const boundaryPatch& bp = patches_[patchI];
820 forAll(bp, patchFaceI)
822 label faceI = bp.start() + patchFaceI;
824 label triVertI = 3*startTri[faceI];
826 for (label faceTriI = 0; faceTriI < nTris[faceI]; faceTriI++)
828 label v0 = triVerts[triVertI++];
829 label v1 = triVerts[triVertI++];
830 label v2 = triVerts[triVertI++];
832 tris[triI++] = labelledTri(v0, v1, v2, patchI);
837 triSurface surf(tris, surfPatches, mesh().points());
839 OFstream surfStream(fName);
841 surf.write(surfStream);
845 // Get index in this (boundaryMesh) of face nearest to each boundary face in
847 // Origininally all triangles/faces of boundaryMesh would be bunged into
848 // one big octree. Problem was that faces on top of each other, differing
849 // only in sign of normal, could not be found separately. It would always
850 // find only one. We could detect that it was probably finding the wrong one
851 // (based on normal) but could not 'tell' the octree to retrieve the other
852 // one (since they occupy exactly the same space)
853 // So now faces get put into different octrees depending on normal.
854 // !It still will not be possible to differentiate between two faces on top
855 // of each other having the same normal
856 Foam::labelList Foam::boundaryMesh::getNearest
858 const primitiveMesh& pMesh,
859 const vector& searchSpan
863 // Divide faces into two bins acc. to normal
864 // - left of splitNormal
866 DynamicList<label> leftFaces(mesh().size()/2);
867 DynamicList<label> rightFaces(mesh().size()/2);
869 forAll(mesh(), bFaceI)
871 scalar sign = mesh().faceNormals()[bFaceI] & splitNormal_;
875 rightFaces.append(bFaceI);
879 leftFaces.append(bFaceI);
888 Pout<< "getNearest :"
889 << " rightBin:" << rightFaces.size()
890 << " leftBin:" << leftFaces.size()
896 treeBoundBox overallBb(mesh().localPoints());
898 // Extend domain slightly (also makes it 3D if was 2D)
899 // Note asymmetry to avoid having faces align with octree cubes.
900 scalar tol = 1E-6 * overallBb.avgDim();
902 point& bbMin = overallBb.min();
907 point& bbMax = overallBb.max();
912 // Create the octrees
913 octree<octreeDataFaceList> leftTree
925 octree<octreeDataFaceList> rightTree
940 Pout<< "getNearest : built trees" << endl;
944 const vectorField& ns = mesh().faceNormals();
948 // Search nearest triangle centre for every polyMesh boundary face
951 labelList nearestBFaceI(pMesh.nFaces() - pMesh.nInternalFaces());
953 treeBoundBox tightest;
955 const scalar searchDim = mag(searchSpan);
957 forAll(nearestBFaceI, patchFaceI)
959 label meshFaceI = pMesh.nInternalFaces() + patchFaceI;
961 const point& ctr = pMesh.faceCentres()[meshFaceI];
963 if (debug && (patchFaceI % 1000) == 0)
965 Pout<< "getNearest : patchFace:" << patchFaceI
966 << " meshFaceI:" << meshFaceI << " ctr:" << ctr << endl;
970 // Get normal from area vector
971 vector n = pMesh.faceAreas()[meshFaceI];
972 scalar area = mag(n);
975 scalar typDim = -GREAT;
976 const face& f = pMesh.faces()[meshFaceI];
980 typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
984 tightest.min() = ctr - searchSpan;
985 tightest.max() = ctr + searchSpan;
986 scalar rightDist = searchDim;
987 label rightI = rightTree.findNearest(ctr, tightest, rightDist);
990 // Search left tree. Note: could start from rightDist bounding box
991 // instead of starting from top.
992 tightest.min() = ctr - searchSpan;
993 tightest.max() = ctr + searchSpan;
994 scalar leftDist = searchDim;
995 label leftI = leftTree.findNearest(ctr, tightest, leftDist);
1000 // No face found in right tree.
1004 // No face found in left tree.
1005 nearestBFaceI[patchFaceI] = -1;
1009 // Found in left but not in right. Choose left regardless if
1010 // correct sign. Note: do we want this?
1011 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1018 // Found in right but not in left. Choose right regardless if
1019 // correct sign. Note: do we want this?
1020 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1024 // Found in both trees. Compare normals.
1026 scalar rightSign = n & ns[rightFaces[rightI]];
1027 scalar leftSign = n & ns[leftFaces[leftI]];
1031 (rightSign > 0 && leftSign > 0)
1032 || (rightSign < 0 && leftSign < 0)
1035 // Both same sign. Choose nearest.
1036 if (rightDist < leftDist)
1038 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1042 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1048 // - if both near enough choose one with correct sign
1049 // - otherwise choose nearest.
1051 // Get local dimension as max of distance between ctr and
1054 typDim *= distanceTol_;
1056 if (rightDist < typDim && leftDist < typDim)
1058 // Different sign and nearby. Choosing matching normal
1061 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1065 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1070 // Different sign but faraway. Choosing nearest.
1071 if (rightDist < leftDist)
1073 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1077 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1085 return nearestBFaceI;
1089 void Foam::boundaryMesh::patchify
1091 const labelList& nearest,
1092 const polyBoundaryMesh& oldPatches,
1097 // 2 cases to be handled:
1098 // A- patches in boundaryMesh patches_
1099 // B- patches not in boundaryMesh patches_ but in polyMesh
1101 // Create maps from patch name to new patch index.
1102 HashTable<label> nameToIndex(2*patches_.size());
1104 Map<word> indexToName(2*patches_.size());
1107 label nNewPatches = patches_.size();
1109 forAll(oldPatches, oldPatchI)
1111 const polyPatch& patch = oldPatches[oldPatchI];
1113 label newPatchI = findPatchID(patch.name());
1115 if (newPatchI != -1)
1117 nameToIndex.insert(patch.name(), newPatchI);
1119 indexToName.insert(newPatchI, patch.name());
1123 // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1125 forAll(patches_, bPatchI)
1127 const boundaryPatch& bp = patches_[bPatchI];
1129 if (!nameToIndex.found(bp.name()))
1131 nameToIndex.insert(bp.name(), bPatchI);
1133 indexToName.insert(bPatchI, bp.name());
1138 // Copy names&type of patches (with zero size) from old mesh as far as
1139 // possible. First patch created gets all boundary faces; all others get
1140 // zero faces (repatched later on). Exception is coupled patches which
1143 List<polyPatch*> newPatchPtrList(nNewPatches);
1145 label meshFaceI = newMesh.nInternalFaces();
1147 // First patch gets all non-coupled faces
1148 label facesToBeDone = newMesh.nFaces() - newMesh.nInternalFaces();
1150 forAll(patches_, bPatchI)
1152 const boundaryPatch& bp = patches_[bPatchI];
1154 label newPatchI = nameToIndex[bp.name()];
1156 // Find corresponding patch in polyMesh
1157 label oldPatchI = findPatchID(oldPatches, bp.name());
1159 if (oldPatchI == -1)
1161 // Newly created patch. Gets all or zero faces.
1164 Pout<< "patchify : Creating new polyPatch:" << bp.name()
1165 << " type:" << bp.physicalType() << endl;
1168 newPatchPtrList[newPatchI] = polyPatch::New
1175 newMesh.boundaryMesh()
1178 meshFaceI += facesToBeDone;
1180 // first patch gets all boundary faces; all others get 0.
1185 // Existing patch. Gets all or zero faces.
1186 const polyPatch& oldPatch = oldPatches[oldPatchI];
1190 Pout<< "patchify : Cloning existing polyPatch:"
1191 << oldPatch.name() << endl;
1194 newPatchPtrList[newPatchI] = oldPatch.clone
1196 newMesh.boundaryMesh(),
1202 meshFaceI += facesToBeDone;
1204 // first patch gets all boundary faces; all others get 0.
1212 Pout<< "Patchify : new polyPatch list:" << endl;
1214 forAll(newPatchPtrList, patchI)
1216 const polyPatch& newPatch = *newPatchPtrList[patchI];
1220 Pout<< "polyPatch:" << newPatch.name() << endl
1221 << " type :" << newPatch.typeName << endl
1222 << " size :" << newPatch.size() << endl
1223 << " start:" << newPatch.start() << endl
1224 << " index:" << patchI << endl;
1229 // Actually add new list of patches
1230 repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1231 polyMeshRepatcher.changePatches(newPatchPtrList);
1235 // Change patch type for face
1237 if (newPatchPtrList.size())
1239 List<DynamicList<label> > patchFaces(nNewPatches);
1241 // Give reasonable estimate for size of patches
1243 (newMesh.nFaces() - newMesh.nInternalFaces())
1246 forAll(patchFaces, newPatchI)
1248 patchFaces[newPatchI].setCapacity(nAvgFaces);
1252 // Sort faces acc. to new patch index. Can loop over all old patches
1253 // since will contain all faces.
1256 forAll(oldPatches, oldPatchI)
1258 const polyPatch& patch = oldPatches[oldPatchI];
1260 forAll(patch, patchFaceI)
1262 // Put face into region given by nearest boundary face
1264 label meshFaceI = patch.start() + patchFaceI;
1266 label bFaceI = meshFaceI - newMesh.nInternalFaces();
1268 patchFaces[whichPatch(nearest[bFaceI])].append(meshFaceI);
1272 forAll(patchFaces, newPatchI)
1274 patchFaces[newPatchI].shrink();
1278 // Change patch > 0. (since above we put all faces into the zeroth
1281 for (label newPatchI = 1; newPatchI < patchFaces.size(); newPatchI++)
1283 const labelList& pFaces = patchFaces[newPatchI];
1285 forAll(pFaces, pFaceI)
1287 polyMeshRepatcher.changePatchID(pFaces[pFaceI], newPatchI);
1291 polyMeshRepatcher.repatch();
1296 void Foam::boundaryMesh::setFeatureEdges(const scalar minCos)
1298 edgeToFeature_.setSize(mesh().nEdges());
1300 edgeToFeature_ = -1;
1302 // 1. Mark feature edges
1304 // Storage for edge labels that are features. Trim later.
1305 featureToEdge_.setSize(mesh().nEdges());
1309 if (minCos >= 0.9999)
1311 // Select everything
1312 forAll(mesh().edges(), edgeI)
1314 edgeToFeature_[edgeI] = featureI;
1315 featureToEdge_[featureI++] = edgeI;
1320 forAll(mesh().edges(), edgeI)
1322 const labelList& eFaces = mesh().edgeFaces()[edgeI];
1324 if (eFaces.size() == 2)
1326 label face0I = eFaces[0];
1328 label face1I = eFaces[1];
1330 ////- Uncomment below code if you want to include patch
1331 //// boundaries in feature edges.
1332 //if (whichPatch(face0I) != whichPatch(face1I))
1334 // edgeToFeature_[edgeI] = featureI;
1335 // featureToEdge_[featureI++] = edgeI;
1339 const vector& n0 = mesh().faceNormals()[face0I];
1341 const vector& n1 = mesh().faceNormals()[face1I];
1343 float cosAng = n0 & n1;
1345 if (cosAng < minCos)
1347 edgeToFeature_[edgeI] = featureI;
1348 featureToEdge_[featureI++] = edgeI;
1354 //Should not occur: 0 or more than two faces
1355 edgeToFeature_[edgeI] = featureI;
1356 featureToEdge_[featureI++] = edgeI;
1361 // Trim featureToEdge_ to actual number of edges.
1362 featureToEdge_.setSize(featureI);
1365 // Compact edges i.e. relabel vertices.
1368 featureEdges_.setSize(featureI);
1369 featurePoints_.setSize(mesh().nPoints());
1371 labelList featToMeshPoint(mesh().nPoints(), -1);
1375 forAll(featureToEdge_, fEdgeI)
1377 label edgeI = featureToEdge_[fEdgeI];
1379 const edge& e = mesh().edges()[edgeI];
1381 label start = featToMeshPoint[e.start()];
1385 featToMeshPoint[e.start()] = featPtI;
1387 featurePoints_[featPtI] = mesh().points()[e.start()];
1394 label end = featToMeshPoint[e.end()];
1398 featToMeshPoint[e.end()] = featPtI;
1400 featurePoints_[featPtI] = mesh().points()[e.end()];
1407 // Store with renumbered vertices.
1408 featureEdges_[fEdgeI] = edge(start, end);
1412 featurePoints_.setSize(featPtI);
1416 // 2. Mark endpoints of feature segments. These are points with
1417 // != 2 feature edges connected.
1418 // Note: can add geometric constraint here as well that if 2 feature
1419 // edges the angle between them should be less than xxx.
1422 boolList isFeaturePoint(mesh().nPoints(), false);
1424 forAll(featureToEdge_, featI)
1426 label edgeI = featureToEdge_[featI];
1428 const edge& e = mesh().edges()[edgeI];
1430 if (nFeatureEdges(e.start()) != 2)
1432 isFeaturePoint[e.start()] = true;
1435 if (nFeatureEdges(e.end()) != 2)
1437 isFeaturePoint[e.end()] = true;
1443 // 3: Split feature edges into segments:
1444 // find point with not 2 feature edges -> start of feature segment
1447 DynamicList<labelList> segments;
1450 boolList featVisited(featureToEdge_.size(), false);
1454 label startFeatI = -1;
1456 forAll(featVisited, featI)
1458 if (!featVisited[featI])
1466 if (startFeatI == -1)
1468 // No feature lines left.
1477 featureToEdge_[startFeatI],
1488 featureSegments_.setSize(segments.size());
1490 forAll(featureSegments_, segmentI)
1492 featureSegments_[segmentI] = segments[segmentI];
1497 void Foam::boundaryMesh::setExtraEdges(const label edgeI)
1499 labelList minDistance(mesh().nEdges(), -1);
1501 // All edge labels encountered
1502 DynamicList<label> visitedEdges;
1504 // Floodfill from edgeI starting from distance 0. Stop at distance.
1505 markEdges(8, edgeI, 0, minDistance, visitedEdges);
1507 // Set edge labels to display
1508 extraEdges_.transfer(visitedEdges);
1512 Foam::label Foam::boundaryMesh::whichPatch(const label faceI) const
1514 forAll(patches_, patchI)
1516 const boundaryPatch& bp = patches_[patchI];
1518 if ((faceI >= bp.start()) && (faceI < (bp.start() + bp.size())))
1524 FatalErrorIn("boundaryMesh::whichPatch(const label)")
1525 << "Cannot find face " << faceI << " in list of boundaryPatches "
1527 << abort(FatalError);
1533 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1535 forAll(patches_, patchI)
1537 if (patches_[patchI].name() == patchName)
1547 void Foam::boundaryMesh::addPatch(const word& patchName)
1549 patches_.setSize(patches_.size() + 1);
1551 // Add empty patch at end of patch list.
1553 label patchI = patches_.size()-1;
1555 boundaryPatch* bpPtr = new boundaryPatch
1564 patches_.set(patchI, bpPtr);
1568 Pout<< "addPatch : patches now:" << endl;
1570 forAll(patches_, patchI)
1572 const boundaryPatch& bp = patches_[patchI];
1574 Pout<< " name : " << bp.name() << endl
1575 << " size : " << bp.size() << endl
1576 << " start : " << bp.start() << endl
1577 << " type : " << bp.physicalType() << endl
1584 void Foam::boundaryMesh::deletePatch(const word& patchName)
1586 label delPatchI = findPatchID(patchName);
1588 if (delPatchI == -1)
1590 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1591 << "Can't find patch named " << patchName
1592 << abort(FatalError);
1595 if (patches_[delPatchI].size())
1597 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1598 << "Trying to delete non-empty patch " << patchName
1599 << endl << "Current size:" << patches_[delPatchI].size()
1600 << abort(FatalError);
1603 PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1605 for (label patchI = 0; patchI < delPatchI; patchI++)
1607 newPatches.set(patchI, patches_[patchI].clone());
1610 // Move patches down, starting from delPatchI.
1612 for (label patchI = delPatchI + 1; patchI < patches_.size(); patchI++)
1614 newPatches.set(patchI - 1, patches_[patchI].clone());
1619 patches_ = newPatches;
1623 Pout<< "deletePatch : patches now:" << endl;
1625 forAll(patches_, patchI)
1627 const boundaryPatch& bp = patches_[patchI];
1629 Pout<< " name : " << bp.name() << endl
1630 << " size : " << bp.size() << endl
1631 << " start : " << bp.start() << endl
1632 << " type : " << bp.physicalType() << endl
1639 void Foam::boundaryMesh::changePatchType
1641 const word& patchName,
1642 const word& patchType
1645 label changeI = findPatchID(patchName);
1649 FatalErrorIn("boundaryMesh::changePatchType(const word&, const word&)")
1650 << "Can't find patch named " << patchName
1651 << abort(FatalError);
1655 // Cause we can't reassign to individual PtrList elems ;-(
1659 PtrList<boundaryPatch> newPatches(patches_.size());
1661 forAll(patches_, patchI)
1663 if (patchI == changeI)
1665 // Create copy but for type
1666 const boundaryPatch& oldBp = patches_[patchI];
1668 boundaryPatch* bpPtr = new boundaryPatch
1677 newPatches.set(patchI, bpPtr);
1682 newPatches.set(patchI, patches_[patchI].clone());
1686 patches_ = newPatches;
1690 void Foam::boundaryMesh::changeFaces
1692 const labelList& patchIDs,
1696 if (patchIDs.size() != mesh().size())
1698 FatalErrorIn("boundaryMesh::changeFaces(const labelList& patchIDs)")
1699 << "List of patchIDs not equal to number of faces." << endl
1700 << "PatchIDs size:" << patchIDs.size()
1701 << " nFaces::" << mesh().size()
1702 << abort(FatalError);
1705 // Count number of faces for each patch
1707 labelList nFaces(patches_.size(), 0);
1709 forAll(patchIDs, faceI)
1711 label patchID = patchIDs[faceI];
1713 if (patchID < 0 || patchID >= patches_.size())
1715 FatalErrorIn("boundaryMesh::changeFaces(const labelList&)")
1716 << "PatchID " << patchID << " out of range"
1717 << abort(FatalError);
1723 // Determine position in faces_ for each patch
1725 labelList startFace(patches_.size());
1729 for (label patchI = 1; patchI < patches_.size(); patchI++)
1731 startFace[patchI] = startFace[patchI-1] + nFaces[patchI-1];
1734 // Update patch info
1735 PtrList<boundaryPatch> newPatches(patches_.size());
1737 forAll(patches_, patchI)
1739 const boundaryPatch& bp = patches_[patchI];
1754 patches_ = newPatches;
1758 Pout<< "changeFaces : patches now:" << endl;
1760 forAll(patches_, patchI)
1762 const boundaryPatch& bp = patches_[patchI];
1764 Pout<< " name : " << bp.name() << endl
1765 << " size : " << bp.size() << endl
1766 << " start : " << bp.start() << endl
1767 << " type : " << bp.physicalType() << endl
1773 // Construct face mapping array
1774 oldToNew.setSize(patchIDs.size());
1776 forAll(patchIDs, faceI)
1778 int patchID = patchIDs[faceI];
1780 oldToNew[faceI] = startFace[patchID]++;
1783 // Copy faces into correct position and maintain label of original face
1784 faceList newFaces(mesh().size());
1786 labelList newMeshFace(mesh().size());
1788 forAll(oldToNew, faceI)
1790 newFaces[oldToNew[faceI]] = mesh()[faceI];
1791 newMeshFace[oldToNew[faceI]] = meshFace_[faceI];
1794 // Reconstruct 'mesh' from new faces and (copy of) existing points.
1795 bMesh* newMeshPtr_ = new bMesh(newFaces, mesh().points());
1797 // Reset meshFace_ to new ordering.
1798 meshFace_.transfer(newMeshFace);
1801 // Remove old PrimitivePatch on meshPtr_.
1804 // And insert new 'mesh'.
1805 meshPtr_ = newMeshPtr_;
1809 Foam::label Foam::boundaryMesh::getNTris(const label faceI) const
1811 const face& f = mesh()[faceI];
1813 return f.nTriangles(mesh().points());
1817 Foam::label Foam::boundaryMesh::getNTris
1819 const label startFaceI,
1824 label totalNTris = 0;
1826 nTris.setSize(nFaces);
1828 for (label i = 0; i < nFaces; i++)
1830 label faceNTris = getNTris(startFaceI + i);
1832 nTris[i] = faceNTris;
1834 totalNTris += faceNTris;
1840 // Simple triangulation of face subset. Stores vertices in tris[] as three
1841 // consecutive vertices per triangle.
1842 void Foam::boundaryMesh::triangulate
1844 const label startFaceI,
1846 const label totalNTris,
1850 // Triangulate faces.
1851 triVerts.setSize(3*totalNTris);
1855 for (label i = 0; i < nFaces; i++)
1857 label faceI = startFaceI + i;
1859 const face& f = mesh()[faceI];
1861 // Have face triangulate itself (results in faceList)
1862 faceList triFaces(f.nTriangles(mesh().points()));
1866 f.triangles(mesh().points(), nTri, triFaces);
1868 // Copy into triVerts
1870 forAll(triFaces, triFaceI)
1872 const face& triF = triFaces[triFaceI];
1874 triVerts[vertI++] = triF[0];
1875 triVerts[vertI++] = triF[1];
1876 triVerts[vertI++] = triF[2];
1882 // Number of local points in subset.
1883 Foam::label Foam::boundaryMesh::getNPoints
1885 const label startFaceI,
1889 SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1891 primitivePatch patch(patchFaces, mesh().points());
1893 return patch.nPoints();
1897 // Triangulation of face subset in local coords.
1898 void Foam::boundaryMesh::triangulateLocal
1900 const label startFaceI,
1902 const label totalNTris,
1903 labelList& triVerts,
1904 labelList& localToGlobal
1907 SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1909 primitivePatch patch(patchFaces, mesh().points());
1911 // Map from local to mesh().points() addressing
1912 localToGlobal = patch.meshPoints();
1914 // Triangulate patch faces.
1915 triVerts.setSize(3*totalNTris);
1919 for (label i = 0; i < nFaces; i++)
1922 const face& f = patch.localFaces()[i];
1924 // Have face triangulate itself (results in faceList)
1925 faceList triFaces(f.nTriangles(patch.localPoints()));
1929 f.triangles(patch.localPoints(), nTri, triFaces);
1931 // Copy into triVerts
1933 forAll(triFaces, triFaceI)
1935 const face& triF = triFaces[triFaceI];
1937 triVerts[vertI++] = triF[0];
1938 triVerts[vertI++] = triF[1];
1939 triVerts[vertI++] = triF[2];
1945 void Foam::boundaryMesh::markFaces
1947 const labelList& protectedEdges,
1948 const label seedFaceI,
1952 boolList protectedEdge(mesh().nEdges(), false);
1954 forAll(protectedEdges, i)
1956 protectedEdge[protectedEdges[i]] = true;
1960 // Initialize zone for all faces to -1
1961 labelList currentZone(mesh().size(), -1);
1963 // Mark with 0 all faces reachable from seedFaceI
1964 markZone(protectedEdge, seedFaceI, 0, currentZone);
1966 // Set in visited all reached ones.
1967 visited.setSize(mesh().size());
1969 forAll(currentZone, faceI)
1971 if (currentZone[faceI] == 0)
1973 visited[faceI] = true;
1977 visited[faceI] = false;
1983 // ************************************************************************* //