1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "boundaryMesh.H"
30 #include "repatchPolyTopoChanger.H"
33 #include "octreeDataFaceList.H"
34 #include "triSurface.H"
35 #include "SortableList.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 defineTypeNameAndDebug(boundaryMesh, 0);
45 // Normal along which to divide faces into categories (used in getNearest)
46 const Foam::vector Foam::boundaryMesh::splitNormal_(3, 2, 1);
48 // Distance to face tolerance for getNearest
49 const Foam::scalar Foam::boundaryMesh::distanceTol_ = 1E-2;
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
54 // Returns number of feature edges connected to pointI
55 Foam::label Foam::boundaryMesh::nFeatureEdges(label pointI) const
59 const labelList& pEdges = mesh().pointEdges()[pointI];
61 forAll(pEdges, pEdgeI)
63 label edgeI = pEdges[pEdgeI];
65 if (edgeToFeature_[edgeI] != -1)
74 // Returns next feature edge connected to pointI
75 Foam::label Foam::boundaryMesh::nextFeatureEdge
81 const labelList& pEdges = mesh().pointEdges()[vertI];
83 forAll(pEdges, pEdgeI)
85 label nbrEdgeI = pEdges[pEdgeI];
87 if (nbrEdgeI != edgeI)
89 label featI = edgeToFeature_[nbrEdgeI];
102 // Finds connected feature edges, starting from startPointI and returns
103 // feature labels (not edge labels). Marks feature edges handled in
105 Foam::labelList Foam::boundaryMesh::collectSegment
107 const boolList& isFeaturePoint,
108 const label startEdgeI,
109 boolList& featVisited
112 // Find starting feature point on edge.
114 label edgeI = startEdgeI;
116 const edge& e = mesh().edges()[edgeI];
118 label vertI = e.start();
120 while (!isFeaturePoint[vertI])
122 // Step to next feature edge
124 edgeI = nextFeatureEdge(edgeI, vertI);
126 if ((edgeI == -1) || (edgeI == startEdgeI))
131 // Step to next vertex on edge
133 const edge& e = mesh().edges()[edgeI];
135 vertI = e.otherVertex(vertI);
140 // edgeI : first edge on this segment
141 // vertI : one of the endpoints of this segment
143 // Start walking other way and storing edges as we go along.
146 // Untrimmed storage for current segment
147 labelList featLabels(featureEdges_.size());
149 label featLabelI = 0;
151 label initEdgeI = edgeI;
155 // Mark edge as visited
156 label featI = edgeToFeature_[edgeI];
160 FatalErrorIn("boundaryMesh::collectSegment")
161 << "Problem" << abort(FatalError);
163 featLabels[featLabelI++] = featI;
165 featVisited[featI] = true;
167 // Step to next vertex on edge
169 const edge& e = mesh().edges()[edgeI];
171 vertI = e.otherVertex(vertI);
173 // Step to next feature edge
175 edgeI = nextFeatureEdge(edgeI, vertI);
177 if ((edgeI == -1) || (edgeI == initEdgeI))
182 while (!isFeaturePoint[vertI]);
186 featLabels.setSize(featLabelI);
192 void Foam::boundaryMesh::markEdges
194 const label maxDistance,
196 const label distance,
197 labelList& minDistance,
198 DynamicList<label>& visited
201 if (distance < maxDistance)
203 // Don't do anything if reached beyond maxDistance.
205 if (minDistance[edgeI] == -1)
207 // First visit of edge. Store edge label.
208 visited.append(edgeI);
210 else if (minDistance[edgeI] <= distance)
212 // Already done this edge
216 minDistance[edgeI] = distance;
218 const edge& e = mesh().edges()[edgeI];
220 // Do edges connected to e.start
221 const labelList& startEdges = mesh().pointEdges()[e.start()];
223 forAll(startEdges, pEdgeI)
235 // Do edges connected to e.end
236 const labelList& endEdges = mesh().pointEdges()[e.end()];
238 forAll(endEdges, pEdgeI)
253 Foam::label Foam::boundaryMesh::findPatchID
255 const polyPatchList& patches,
256 const word& patchName
259 forAll(patches, patchI)
261 if (patches[patchI].name() == patchName)
271 Foam::wordList Foam::boundaryMesh::patchNames() const
273 wordList names(patches_.size());
275 forAll(patches_, patchI)
277 names[patchI] = patches_[patchI].name();
283 Foam::label Foam::boundaryMesh::whichPatch
285 const polyPatchList& patches,
289 forAll(patches, patchI)
291 const polyPatch& pp = patches[patchI];
293 if ((faceI >= pp.start()) && (faceI < (pp.start() + pp.size())))
302 // Gets labels of changed faces and propagates them to the edges. Returns
303 // labels of edges changed.
304 Foam::labelList Foam::boundaryMesh::faceToEdge
306 const boolList& regionEdge,
308 const labelList& changedFaces,
309 labelList& edgeRegion
312 labelList changedEdges(mesh().nEdges(), -1);
315 forAll(changedFaces, i)
317 label faceI = changedFaces[i];
319 const labelList& fEdges = mesh().faceEdges()[faceI];
321 forAll(fEdges, fEdgeI)
323 label edgeI = fEdges[fEdgeI];
325 if (!regionEdge[edgeI] && (edgeRegion[edgeI] == -1))
327 edgeRegion[edgeI] = region;
329 changedEdges[changedI++] = edgeI;
334 changedEdges.setSize(changedI);
340 // Reverse of faceToEdge: gets edges and returns faces
341 Foam::labelList Foam::boundaryMesh::edgeToFace
344 const labelList& changedEdges,
345 labelList& faceRegion
348 labelList changedFaces(mesh().size(), -1);
351 forAll(changedEdges, i)
353 label edgeI = changedEdges[i];
355 const labelList& eFaces = mesh().edgeFaces()[edgeI];
357 forAll(eFaces, eFaceI)
359 label faceI = eFaces[eFaceI];
361 if (faceRegion[faceI] == -1)
363 faceRegion[faceI] = region;
365 changedFaces[changedI++] = faceI;
370 changedFaces.setSize(changedI);
376 // Finds area, starting at faceI, delimited by borderEdge
377 void Foam::boundaryMesh::markZone
379 const boolList& borderEdge,
385 faceZone[faceI] = currentZone;
387 // List of faces whose faceZone has been set.
388 labelList changedFaces(1, faceI);
389 // List of edges whose faceZone has been set.
390 labelList changedEdges;
392 // Zones on all edges.
393 labelList edgeZone(mesh().nEdges(), -1);
408 Pout<< "From changedFaces:" << changedFaces.size()
409 << " to changedEdges:" << changedEdges.size()
413 if (changedEdges.size() == 0)
418 changedFaces = edgeToFace(currentZone, changedEdges, faceZone);
422 Pout<< "From changedEdges:" << changedEdges.size()
423 << " to changedFaces:" << changedFaces.size()
427 if (changedFaces.size() == 0)
435 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
438 Foam::boundaryMesh::boundaryMesh()
452 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
454 Foam::boundaryMesh::~boundaryMesh()
460 void Foam::boundaryMesh::clearOut()
471 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
473 void Foam::boundaryMesh::read(const polyMesh& mesh)
477 patches_.setSize(mesh.boundaryMesh().size());
479 // Number of boundary faces
480 label nBFaces = mesh.nFaces() - mesh.nInternalFaces();
482 faceList bFaces(nBFaces);
484 meshFace_.setSize(nBFaces);
488 // Collect all boundary faces.
489 forAll(mesh.boundaryMesh(), patchI)
491 const polyPatch& pp = mesh.boundaryMesh()[patchI];
506 // Collect all faces in global numbering.
507 forAll(pp, patchFaceI)
509 meshFace_[bFaceI] = pp.start() + patchFaceI;
511 bFaces[bFaceI] = pp[patchFaceI];
520 Pout<< "read : patches now:" << endl;
522 forAll(patches_, patchI)
524 const boundaryPatch& bp = patches_[patchI];
526 Pout<< " name : " << bp.name() << endl
527 << " size : " << bp.size() << endl
528 << " start : " << bp.start() << endl
529 << " type : " << bp.physicalType() << endl
535 // Construct single patch for all of boundary
538 // Temporary primitivePatch to calculate compact points & faces.
539 PrimitivePatch<face, List, const pointField&> globalPatch
545 // Store in local(compact) addressing
548 meshPtr_ = new bMesh(globalPatch.localFaces(), globalPatch.localPoints());
553 const bMesh& msh = *meshPtr_;
555 Pout<< "** Start of Faces **" << endl;
559 const face& f = msh[faceI];
561 point ctr(vector::zero);
565 ctr += msh.points()[f[fp]];
575 Pout<< "** End of Faces **" << endl;
577 Pout<< "** Start of Points **" << endl;
579 forAll(msh.points(), pointI)
582 << " coord:" << msh.points()[pointI]
586 Pout<< "** End of Points **" << endl;
589 // Clear edge storage
590 featurePoints_.setSize(0);
591 featureEdges_.setSize(0);
593 featureToEdge_.setSize(0);
594 edgeToFeature_.setSize(meshPtr_->nEdges());
597 featureSegments_.setSize(0);
599 extraEdges_.setSize(0);
603 void Foam::boundaryMesh::readTriSurface(const fileName& fName)
605 triSurface surf(fName);
607 if (surf.size() <= 0)
612 // Sort according to region
613 SortableList<label> regions(surf.size());
617 regions[triI] = surf[triI].region();
621 // Determine region mapping.
622 Map<label> regionToBoundaryPatch;
624 label oldRegion = -1111;
625 label boundPatch = 0;
629 if (regions[i] != oldRegion)
631 regionToBoundaryPatch.insert(regions[i], boundPatch);
633 oldRegion = regions[i];
638 const geometricSurfacePatchList& surfPatches = surf.patches();
642 if (surfPatches.size() == regionToBoundaryPatch.size())
644 // There are as many surface patches as region numbers in triangles
645 // so use the surface patches
647 patches_.setSize(surfPatches.size());
649 // Take over patches, setting size to 0 for now.
650 forAll(surfPatches, patchI)
652 const geometricSurfacePatch& surfPatch = surfPatches[patchI];
663 surfPatch.geometricType()
670 // There are not enough surface patches. Make up my own.
672 patches_.setSize(regionToBoundaryPatch.size());
674 forAll(patches_, patchI)
681 "patch" + name(patchI),
692 // Copy according into bFaces according to regions
695 const labelList& indices = regions.indices();
697 faceList bFaces(surf.size());
699 meshFace_.setSize(surf.size());
703 // Current region number
704 label surfRegion = regions[0];
705 label foamRegion = regionToBoundaryPatch[surfRegion];
707 Pout<< "Surface region " << surfRegion << " becomes boundary patch "
708 << foamRegion << " with name " << patches_[foamRegion].name() << endl;
711 // Index in bFaces of start of current patch
712 label startFaceI = 0;
714 forAll(indices, indexI)
716 label triI = indices[indexI];
718 const labelledTri& tri = surf.localFaces()[triI];
720 if (tri.region() != surfRegion)
722 // Change of region. We now know the size of the previous one.
723 boundaryPatch& bp = patches_[foamRegion];
725 bp.size() = bFaceI - startFaceI;
726 bp.start() = startFaceI;
728 surfRegion = tri.region();
729 foamRegion = regionToBoundaryPatch[surfRegion];
731 Pout<< "Surface region " << surfRegion << " becomes boundary patch "
732 << foamRegion << " with name " << patches_[foamRegion].name()
738 meshFace_[bFaceI] = triI;
740 bFaces[bFaceI++] = face(tri);
744 boundaryPatch& bp = patches_[foamRegion];
746 bp.size() = bFaceI - startFaceI;
747 bp.start() = startFaceI;
750 // Construct single primitivePatch for all of boundary
756 meshPtr_ = new bMesh(bFaces, surf.localPoints());
758 // Clear edge storage
759 featurePoints_.setSize(0);
760 featureEdges_.setSize(0);
762 featureToEdge_.setSize(0);
763 edgeToFeature_.setSize(meshPtr_->nEdges());
766 featureSegments_.setSize(0);
768 extraEdges_.setSize(0);
772 void Foam::boundaryMesh::writeTriSurface(const fileName& fName) const
774 geometricSurfacePatchList surfPatches(patches_.size());
776 forAll(patches_, patchI)
778 const boundaryPatch& bp = patches_[patchI];
780 surfPatches[patchI] =
781 geometricSurfacePatch
790 // Simple triangulation.
793 // Get number of triangles per face
794 labelList nTris(mesh().size());
796 label totalNTris = getNTris(0, mesh().size(), nTris);
798 // Determine per face the starting triangle.
799 labelList startTri(mesh().size());
803 forAll(mesh(), faceI)
805 startTri[faceI] = triI;
807 triI += nTris[faceI];
811 labelList triVerts(3*totalNTris);
813 triangulate(0, mesh().size(), totalNTris, triVerts);
815 // Convert to labelledTri
817 List<labelledTri> tris(totalNTris);
821 forAll(patches_, patchI)
823 const boundaryPatch& bp = patches_[patchI];
825 forAll(bp, patchFaceI)
827 label faceI = bp.start() + patchFaceI;
829 label triVertI = 3*startTri[faceI];
831 for (label faceTriI = 0; faceTriI < nTris[faceI]; faceTriI++)
833 label v0 = triVerts[triVertI++];
834 label v1 = triVerts[triVertI++];
835 label v2 = triVerts[triVertI++];
837 tris[triI++] = labelledTri(v0, v1, v2, patchI);
842 triSurface surf(tris, surfPatches, mesh().points());
844 OFstream surfStream(fName);
846 surf.write(surfStream);
850 // Get index in this (boundaryMesh) of face nearest to each boundary face in
852 // Origininally all triangles/faces of boundaryMesh would be bunged into
853 // one big octree. Problem was that faces on top of each other, differing
854 // only in sign of normal, could not be found separately. It would always
855 // find only one. We could detect that it was probably finding the wrong one
856 // (based on normal) but could not 'tell' the octree to retrieve the other
857 // one (since they occupy exactly the same space)
858 // So now faces get put into different octrees depending on normal.
859 // !It still will not be possible to differentiate between two faces on top
860 // of each other having the same normal
861 Foam::labelList Foam::boundaryMesh::getNearest
863 const primitiveMesh& pMesh,
864 const vector& searchSpan
868 // Divide faces into two bins acc. to normal
869 // - left of splitNormal
871 DynamicList<label> leftFaces(mesh().size()/2);
872 DynamicList<label> rightFaces(mesh().size()/2);
874 forAll(mesh(), bFaceI)
876 scalar sign = mesh().faceNormals()[bFaceI] & splitNormal_;
880 rightFaces.append(bFaceI);
884 leftFaces.append(bFaceI);
893 Pout<< "getNearest :"
894 << " rightBin:" << rightFaces.size()
895 << " leftBin:" << leftFaces.size()
901 treeBoundBox overallBb(mesh().localPoints());
903 // Extend domain slightly (also makes it 3D if was 2D)
904 // Note asymmetry to avoid having faces align with octree cubes.
905 scalar tol = 1E-6*overallBb.avgDim();
907 point& bbMin = overallBb.min();
912 point& bbMax = overallBb.max();
917 // Create the octrees
918 octree<octreeDataFaceList> leftTree
930 octree<octreeDataFaceList> rightTree
945 Pout<< "getNearest : built trees" << endl;
949 const vectorField& ns = mesh().faceNormals();
953 // Search nearest triangle centre for every polyMesh boundary face
956 labelList nearestBFaceI(pMesh.nFaces() - pMesh.nInternalFaces());
958 treeBoundBox tightest;
960 const scalar searchDim = mag(searchSpan);
962 forAll(nearestBFaceI, patchFaceI)
964 label meshFaceI = pMesh.nInternalFaces() + patchFaceI;
966 const point& ctr = pMesh.faceCentres()[meshFaceI];
968 if (debug && (patchFaceI % 1000) == 0)
970 Pout<< "getNearest : patchFace:" << patchFaceI
971 << " meshFaceI:" << meshFaceI << " ctr:" << ctr << endl;
975 // Get normal from area vector
976 vector n = pMesh.faceAreas()[meshFaceI];
977 scalar area = mag(n);
980 scalar typDim = -GREAT;
981 const face& f = pMesh.faces()[meshFaceI];
985 typDim = max(typDim, mag(pMesh.points()[f[fp]] - ctr));
989 tightest.min() = ctr - searchSpan;
990 tightest.max() = ctr + searchSpan;
991 scalar rightDist = searchDim;
992 label rightI = rightTree.findNearest(ctr, tightest, rightDist);
995 // Search left tree. Note: could start from rightDist bounding box
996 // instead of starting from top.
997 tightest.min() = ctr - searchSpan;
998 tightest.max() = ctr + searchSpan;
999 scalar leftDist = searchDim;
1000 label leftI = leftTree.findNearest(ctr, tightest, leftDist);
1005 // No face found in right tree.
1009 // No face found in left tree.
1010 nearestBFaceI[patchFaceI] = -1;
1014 // Found in left but not in right. Choose left regardless if
1015 // correct sign. Note: do we want this?
1016 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1023 // Found in right but not in left. Choose right regardless if
1024 // correct sign. Note: do we want this?
1025 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1029 // Found in both trees. Compare normals.
1031 scalar rightSign = n & ns[rightFaces[rightI]];
1032 scalar leftSign = n & ns[leftFaces[leftI]];
1036 (rightSign > 0 && leftSign > 0)
1037 || (rightSign < 0 && leftSign < 0)
1040 // Both same sign. Choose nearest.
1041 if (rightDist < leftDist)
1043 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1047 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1053 // - if both near enough choose one with correct sign
1054 // - otherwise choose nearest.
1056 // Get local dimension as max of distance between ctr and
1059 typDim *= distanceTol_;
1061 if (rightDist < typDim && leftDist < typDim)
1063 // Different sign and nearby. Choosing matching normal
1066 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1070 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1075 // Different sign but faraway. Choosing nearest.
1076 if (rightDist < leftDist)
1078 nearestBFaceI[patchFaceI] = rightFaces[rightI];
1082 nearestBFaceI[patchFaceI] = leftFaces[leftI];
1090 return nearestBFaceI;
1094 void Foam::boundaryMesh::patchify
1096 const labelList& nearest,
1097 const polyBoundaryMesh& oldPatches,
1102 // 2 cases to be handled:
1103 // A- patches in boundaryMesh patches_
1104 // B- patches not in boundaryMesh patches_ but in polyMesh
1106 // Create maps from patch name to new patch index.
1107 HashTable<label> nameToIndex(2*patches_.size());
1109 Map<word> indexToName(2*patches_.size());
1112 label nNewPatches = patches_.size();
1114 forAll(oldPatches, oldPatchI)
1116 const polyPatch& patch = oldPatches[oldPatchI];
1118 label newPatchI = findPatchID(patch.name());
1120 if (newPatchI != -1)
1122 nameToIndex.insert(patch.name(), newPatchI);
1124 indexToName.insert(newPatchI, patch.name());
1128 // Include all boundaryPatches not yet in nameToIndex (i.e. not in old
1130 forAll(patches_, bPatchI)
1132 const boundaryPatch& bp = patches_[bPatchI];
1134 if (!nameToIndex.found(bp.name()))
1136 nameToIndex.insert(bp.name(), bPatchI);
1138 indexToName.insert(bPatchI, bp.name());
1143 // Copy names&type of patches (with zero size) from old mesh as far as
1144 // possible. First patch created gets all boundary faces; all others get
1145 // zero faces (repatched later on). Exception is coupled patches which
1148 List<polyPatch*> newPatchPtrList(nNewPatches);
1150 label meshFaceI = newMesh.nInternalFaces();
1152 // First patch gets all non-coupled faces
1153 label facesToBeDone = newMesh.nFaces() - newMesh.nInternalFaces();
1155 forAll(patches_, bPatchI)
1157 const boundaryPatch& bp = patches_[bPatchI];
1159 label newPatchI = nameToIndex[bp.name()];
1161 // Find corresponding patch in polyMesh
1162 label oldPatchI = findPatchID(oldPatches, bp.name());
1164 if (oldPatchI == -1)
1166 // Newly created patch. Gets all or zero faces.
1169 Pout<< "patchify : Creating new polyPatch:" << bp.name()
1170 << " type:" << bp.physicalType() << endl;
1173 newPatchPtrList[newPatchI] = polyPatch::New
1180 newMesh.boundaryMesh()
1183 meshFaceI += facesToBeDone;
1185 // first patch gets all boundary faces; all others get 0.
1190 // Existing patch. Gets all or zero faces.
1191 const polyPatch& oldPatch = oldPatches[oldPatchI];
1195 Pout<< "patchify : Cloning existing polyPatch:"
1196 << oldPatch.name() << endl;
1199 newPatchPtrList[newPatchI] = oldPatch.clone
1201 newMesh.boundaryMesh(),
1207 meshFaceI += facesToBeDone;
1209 // first patch gets all boundary faces; all others get 0.
1217 Pout<< "Patchify : new polyPatch list:" << endl;
1219 forAll(newPatchPtrList, patchI)
1221 const polyPatch& newPatch = *newPatchPtrList[patchI];
1225 Pout<< "polyPatch:" << newPatch.name() << endl
1226 << " type :" << newPatch.typeName << endl
1227 << " size :" << newPatch.size() << endl
1228 << " start:" << newPatch.start() << endl
1229 << " index:" << patchI << endl;
1234 // Actually add new list of patches
1235 repatchPolyTopoChanger polyMeshRepatcher(newMesh);
1236 polyMeshRepatcher.changePatches(newPatchPtrList);
1240 // Change patch type for face
1242 if (newPatchPtrList.size() > 0)
1244 List<DynamicList<label> > patchFaces(nNewPatches);
1246 // Give reasonable estimate for size of patches
1248 (newMesh.nFaces() - newMesh.nInternalFaces())
1251 forAll(patchFaces, newPatchI)
1253 patchFaces[newPatchI].setSize(nAvgFaces);
1257 // Sort faces acc. to new patch index. Can loop over all old patches
1258 // since will contain all faces.
1261 forAll(oldPatches, oldPatchI)
1263 const polyPatch& patch = oldPatches[oldPatchI];
1265 forAll(patch, patchFaceI)
1267 // Put face into region given by nearest boundary face
1269 label meshFaceI = patch.start() + patchFaceI;
1271 label bFaceI = meshFaceI - newMesh.nInternalFaces();
1273 patchFaces[whichPatch(nearest[bFaceI])].append(meshFaceI);
1277 forAll(patchFaces, newPatchI)
1279 patchFaces[newPatchI].shrink();
1283 // Change patch > 0. (since above we put all faces into the zeroth
1286 for (label newPatchI = 1; newPatchI < patchFaces.size(); newPatchI++)
1288 const labelList& pFaces = patchFaces[newPatchI];
1290 forAll(pFaces, pFaceI)
1292 polyMeshRepatcher.changePatchID(pFaces[pFaceI], newPatchI);
1296 polyMeshRepatcher.repatch();
1301 void Foam::boundaryMesh::setFeatureEdges(const scalar minCos)
1303 edgeToFeature_.setSize(mesh().nEdges());
1305 edgeToFeature_ = -1;
1307 // 1. Mark feature edges
1309 // Storage for edge labels that are features. Trim later.
1310 featureToEdge_.setSize(mesh().nEdges());
1314 if (minCos >= 0.9999)
1316 // Select everything
1317 forAll(mesh().edges(), edgeI)
1319 edgeToFeature_[edgeI] = featureI;
1320 featureToEdge_[featureI++] = edgeI;
1325 forAll(mesh().edges(), edgeI)
1327 const labelList& eFaces = mesh().edgeFaces()[edgeI];
1329 if (eFaces.size() == 2)
1331 label face0I = eFaces[0];
1333 label face1I = eFaces[1];
1335 ////- Uncomment below code if you want to include patch
1336 //// boundaries in feature edges.
1337 //if (whichPatch(face0I) != whichPatch(face1I))
1339 // edgeToFeature_[edgeI] = featureI;
1340 // featureToEdge_[featureI++] = edgeI;
1344 const vector& n0 = mesh().faceNormals()[face0I];
1346 const vector& n1 = mesh().faceNormals()[face1I];
1348 float cosAng = n0 & n1;
1350 if (cosAng < minCos)
1352 edgeToFeature_[edgeI] = featureI;
1353 featureToEdge_[featureI++] = edgeI;
1359 //Should not occur: 0 or more than two faces
1360 edgeToFeature_[edgeI] = featureI;
1361 featureToEdge_[featureI++] = edgeI;
1366 // Trim featureToEdge_ to actual number of edges.
1367 featureToEdge_.setSize(featureI);
1370 // Compact edges i.e. relabel vertices.
1373 featureEdges_.setSize(featureI);
1374 featurePoints_.setSize(mesh().nPoints());
1376 labelList featToMeshPoint(mesh().nPoints(), -1);
1380 forAll(featureToEdge_, fEdgeI)
1382 label edgeI = featureToEdge_[fEdgeI];
1384 const edge& e = mesh().edges()[edgeI];
1386 label start = featToMeshPoint[e.start()];
1390 featToMeshPoint[e.start()] = featPtI;
1392 featurePoints_[featPtI] = mesh().points()[e.start()];
1399 label end = featToMeshPoint[e.end()];
1403 featToMeshPoint[e.end()] = featPtI;
1405 featurePoints_[featPtI] = mesh().points()[e.end()];
1412 // Store with renumbered vertices.
1413 featureEdges_[fEdgeI] = edge(start, end);
1417 featurePoints_.setSize(featPtI);
1421 // 2. Mark endpoints of feature segments. These are points with
1422 // != 2 feature edges connected.
1423 // Note: can add geometric constraint here as well that if 2 feature
1424 // edges the angle between them should be less than xxx.
1427 boolList isFeaturePoint(mesh().nPoints(), false);
1429 forAll(featureToEdge_, featI)
1431 label edgeI = featureToEdge_[featI];
1433 const edge& e = mesh().edges()[edgeI];
1435 if (nFeatureEdges(e.start()) != 2)
1437 isFeaturePoint[e.start()] = true;
1440 if (nFeatureEdges(e.end()) != 2)
1442 isFeaturePoint[e.end()] = true;
1448 // 3: Split feature edges into segments:
1449 // find point with not 2 feature edges -> start of feature segment
1452 DynamicList<labelList> segments;
1455 boolList featVisited(featureToEdge_.size(), false);
1459 label startFeatI = -1;
1461 forAll(featVisited, featI)
1463 if (!featVisited[featI])
1471 if (startFeatI == -1)
1473 // No feature lines left.
1482 featureToEdge_[startFeatI],
1493 featureSegments_.setSize(segments.size());
1495 forAll(featureSegments_, segmentI)
1497 featureSegments_[segmentI] = segments[segmentI];
1502 void Foam::boundaryMesh::setExtraEdges(const label edgeI)
1504 labelList minDistance(mesh().nEdges(), -1);
1506 // All edge labels encountered
1508 DynamicList<label> visitedEdges;
1510 // Floodfill from edgeI starting from distance 0. Stop at distance.
1511 markEdges(8, edgeI, 0, minDistance, visitedEdges);
1513 visitedEdges.shrink();
1515 // Set edge labels to display
1516 //? Allowed to transfer from DynamicList to List
1517 extraEdges_.transfer(visitedEdges);
1521 Foam::label Foam::boundaryMesh::whichPatch(const label faceI) const
1523 forAll(patches_, patchI)
1525 const boundaryPatch& bp = patches_[patchI];
1527 if ((faceI >= bp.start()) && (faceI < (bp.start() + bp.size())))
1533 FatalErrorIn("boundaryMesh::whichPatch(const label)")
1534 << "Cannot find face " << faceI << " in list of boundaryPatches "
1536 << abort(FatalError);
1542 Foam::label Foam::boundaryMesh::findPatchID(const word& patchName) const
1544 forAll(patches_, patchI)
1546 if (patches_[patchI].name() == patchName)
1556 void Foam::boundaryMesh::addPatch(const word& patchName)
1558 patches_.setSize(patches_.size() + 1);
1560 // Add empty patch at end of patch list.
1562 label patchI = patches_.size()-1;
1564 boundaryPatch* bpPtr = new boundaryPatch
1573 patches_.set(patchI, bpPtr);
1577 Pout<< "addPatch : patches now:" << endl;
1579 forAll(patches_, patchI)
1581 const boundaryPatch& bp = patches_[patchI];
1583 Pout<< " name : " << bp.name() << endl
1584 << " size : " << bp.size() << endl
1585 << " start : " << bp.start() << endl
1586 << " type : " << bp.physicalType() << endl
1593 void Foam::boundaryMesh::deletePatch(const word& patchName)
1595 label delPatchI = findPatchID(patchName);
1597 if (delPatchI == -1)
1599 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1600 << "Can't find patch named " << patchName
1601 << abort(FatalError);
1604 if (patches_[delPatchI].size() != 0)
1606 FatalErrorIn("boundaryMesh::deletePatch(const word&")
1607 << "Trying to delete non-empty patch " << patchName
1608 << endl << "Current size:" << patches_[delPatchI].size()
1609 << abort(FatalError);
1612 PtrList<boundaryPatch> newPatches(patches_.size() - 1);
1614 for (label patchI = 0; patchI < delPatchI; patchI++)
1616 newPatches.set(patchI, patches_[patchI].clone());
1619 // Move patches down, starting from delPatchI.
1621 for (label patchI = delPatchI + 1; patchI < patches_.size(); patchI++)
1623 newPatches.set(patchI - 1, patches_[patchI].clone());
1628 patches_ = newPatches;
1632 Pout<< "deletePatch : patches now:" << endl;
1634 forAll(patches_, patchI)
1636 const boundaryPatch& bp = patches_[patchI];
1638 Pout<< " name : " << bp.name() << endl
1639 << " size : " << bp.size() << endl
1640 << " start : " << bp.start() << endl
1641 << " type : " << bp.physicalType() << endl
1648 void Foam::boundaryMesh::changePatchType
1650 const word& patchName,
1651 const word& patchType
1654 label changeI = findPatchID(patchName);
1658 FatalErrorIn("boundaryMesh::changePatchType(const word&, const word&)")
1659 << "Can't find patch named " << patchName
1660 << abort(FatalError);
1664 // Cause we can't reassign to individual PtrList elems ;-(
1668 PtrList<boundaryPatch> newPatches(patches_.size());
1670 forAll(patches_, patchI)
1672 if (patchI == changeI)
1674 // Create copy but for type
1675 const boundaryPatch& oldBp = patches_[patchI];
1677 boundaryPatch* bpPtr = new boundaryPatch
1686 newPatches.set(patchI, bpPtr);
1691 newPatches.set(patchI, patches_[patchI].clone());
1695 patches_ = newPatches;
1699 void Foam::boundaryMesh::changeFaces
1701 const labelList& patchIDs,
1705 if (patchIDs.size() != mesh().size())
1707 FatalErrorIn("boundaryMesh::changeFaces(const labelList& patchIDs)")
1708 << "List of patchIDs not equal to number of faces." << endl
1709 << "PatchIDs size:" << patchIDs.size()
1710 << " nFaces::" << mesh().size()
1711 << abort(FatalError);
1714 // Count number of faces for each patch
1716 labelList nFaces(patches_.size(), 0);
1718 forAll(patchIDs, faceI)
1720 label patchID = patchIDs[faceI];
1722 if ((patchID < 0) || (patchID >= patches_.size()))
1724 FatalErrorIn("boundaryMesh::changeFaces(const labelList&)")
1725 << "PatchID " << patchID << " out of range"
1726 << abort(FatalError);
1732 // Determine position in faces_ for each patch
1734 labelList startFace(patches_.size());
1738 for (label patchI = 1; patchI < patches_.size(); patchI++)
1740 startFace[patchI] = startFace[patchI-1] + nFaces[patchI-1];
1743 // Update patch info
1744 PtrList<boundaryPatch> newPatches(patches_.size());
1746 forAll(patches_, patchI)
1748 const boundaryPatch& bp = patches_[patchI];
1763 patches_ = newPatches;
1767 Pout<< "changeFaces : patches now:" << endl;
1769 forAll(patches_, patchI)
1771 const boundaryPatch& bp = patches_[patchI];
1773 Pout<< " name : " << bp.name() << endl
1774 << " size : " << bp.size() << endl
1775 << " start : " << bp.start() << endl
1776 << " type : " << bp.physicalType() << endl
1782 // Construct face mapping array
1783 oldToNew.setSize(patchIDs.size());
1785 forAll(patchIDs, faceI)
1787 int patchID = patchIDs[faceI];
1789 oldToNew[faceI] = startFace[patchID]++;
1792 // Copy faces into correct position and maintain label of original face
1793 faceList newFaces(mesh().size());
1795 labelList newMeshFace(mesh().size());
1797 forAll(oldToNew, faceI)
1799 newFaces[oldToNew[faceI]] = mesh()[faceI];
1800 newMeshFace[oldToNew[faceI]] = meshFace_[faceI];
1803 // Reconstruct 'mesh' from new faces and (copy of) existing points.
1804 bMesh* newMeshPtr_ = new bMesh(newFaces, mesh().points());
1806 // Reset meshFace_ to new ordering.
1807 meshFace_.transfer(newMeshFace);
1810 // Remove old PrimitivePatch on meshPtr_.
1813 // And insert new 'mesh'.
1814 meshPtr_ = newMeshPtr_;
1818 Foam::label Foam::boundaryMesh::getNTris(const label faceI) const
1820 const face& f = mesh()[faceI];
1822 return f.nTriangles(mesh().points());
1826 Foam::label Foam::boundaryMesh::getNTris
1828 const label startFaceI,
1833 label totalNTris = 0;
1835 nTris.setSize(nFaces);
1837 for (label i = 0; i < nFaces; i++)
1839 label faceNTris = getNTris(startFaceI + i);
1841 nTris[i] = faceNTris;
1843 totalNTris += faceNTris;
1849 // Simple triangulation of face subset. Stores vertices in tris[] as three
1850 // consecutive vertices per triangle.
1851 void Foam::boundaryMesh::triangulate
1853 const label startFaceI,
1855 const label totalNTris,
1859 // Triangulate faces.
1860 triVerts.setSize(3*totalNTris);
1864 for (label i = 0; i < nFaces; i++)
1866 label faceI = startFaceI + i;
1868 const face& f = mesh()[faceI];
1870 // Have face triangulate itself (results in faceList)
1871 faceList triFaces(f.nTriangles(mesh().points()));
1875 f.triangles(mesh().points(), nTri, triFaces);
1877 // Copy into triVerts
1879 forAll(triFaces, triFaceI)
1881 const face& triF = triFaces[triFaceI];
1883 triVerts[vertI++] = triF[0];
1884 triVerts[vertI++] = triF[1];
1885 triVerts[vertI++] = triF[2];
1891 // Number of local points in subset.
1892 Foam::label Foam::boundaryMesh::getNPoints
1894 const label startFaceI,
1898 SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1900 primitivePatch patch(patchFaces, mesh().points());
1902 return patch.nPoints();
1906 // Triangulation of face subset in local coords.
1907 void Foam::boundaryMesh::triangulateLocal
1909 const label startFaceI,
1911 const label totalNTris,
1912 labelList& triVerts,
1913 labelList& localToGlobal
1916 SubList<face> patchFaces(mesh(), nFaces, startFaceI);
1918 primitivePatch patch(patchFaces, mesh().points());
1920 // Map from local to mesh().points() addressing
1921 localToGlobal = patch.meshPoints();
1923 // Triangulate patch faces.
1924 triVerts.setSize(3*totalNTris);
1928 for (label i = 0; i < nFaces; i++)
1931 const face& f = patch.localFaces()[i];
1933 // Have face triangulate itself (results in faceList)
1934 faceList triFaces(f.nTriangles(patch.localPoints()));
1938 f.triangles(patch.localPoints(), nTri, triFaces);
1940 // Copy into triVerts
1942 forAll(triFaces, triFaceI)
1944 const face& triF = triFaces[triFaceI];
1946 triVerts[vertI++] = triF[0];
1947 triVerts[vertI++] = triF[1];
1948 triVerts[vertI++] = triF[2];
1954 void Foam::boundaryMesh::markFaces
1956 const labelList& protectedEdges,
1957 const label seedFaceI,
1961 boolList protectedEdge(mesh().nEdges(), false);
1963 forAll(protectedEdges, i)
1965 protectedEdge[protectedEdges[i]] = true;
1969 // Initialize zone for all faces to -1
1970 labelList currentZone(mesh().size(), -1);
1972 // Mark with 0 all faces reachable from seedFaceI
1973 markZone(protectedEdge, seedFaceI, 0, currentZone);
1975 // Set in visited all reached ones.
1976 visited.setSize(mesh().size());
1978 forAll(currentZone, faceI)
1980 if (currentZone[faceI] == 0)
1982 visited[faceI] = true;
1986 visited[faceI] = false;
1992 // ************************************************************************* //