1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 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
28 \*---------------------------------------------------------------------------*/
30 #include "polyDualMesh.H"
31 #include "meshTools.H"
34 #include "SortableList.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(polyDualMesh, 0);
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 // Determine order for faces:
47 // - upper-triangular order for internal faces
48 // - external faces after internal faces (were already so)
49 Foam::labelList Foam::polyDualMesh::getFaceOrder
51 const labelList& faceOwner,
52 const labelList& faceNeighbour,
53 const cellList& cells,
57 labelList oldToNew(faceOwner.size(), -1);
59 // First unassigned face
64 const labelList& cFaces = cells[cellI];
66 SortableList<label> nbr(cFaces.size());
70 label faceI = cFaces[i];
72 label nbrCellI = faceNeighbour[faceI];
76 // Internal face. Get cell on other side.
77 if (nbrCellI == cellI)
79 nbrCellI = faceOwner[faceI];
89 // nbrCell is master. Let it handle this face.
95 // External face. Do later.
106 oldToNew[cFaces[nbr.indices()[i]]] = newFaceI++;
111 nInternalFaces = newFaceI;
113 Pout<< "nInternalFaces:" << nInternalFaces << endl;
114 Pout<< "nFaces:" << faceOwner.size() << endl;
115 Pout<< "nCells:" << cells.size() << endl;
117 // Leave patch faces intact.
118 for (label faceI = newFaceI; faceI < faceOwner.size(); faceI++)
120 oldToNew[faceI] = faceI;
124 // Check done all faces.
125 forAll(oldToNew, faceI)
127 if (oldToNew[faceI] == -1)
131 "polyDualMesh::getFaceOrder"
132 "(const labelList&, const labelList&, const label) const"
133 ) << "Did not determine new position"
134 << " for face " << faceI
135 << abort(FatalError);
143 // Get the two edges on faceI using pointI. Returns them such that the order
144 // - otherVertex of e0
146 // - otherVertex(pointI) of e1
148 void Foam::polyDualMesh::getPointEdges
150 const primitivePatch& patch,
157 const labelList& fEdges = patch.faceEdges()[faceI];
158 const face& f = patch.localFaces()[faceI];
165 label edgeI = fEdges[i];
167 const edge& e = patch.edges()[edgeI];
171 // One of the edges using pointI. Check which one.
172 label index = findIndex(f, pointI);
174 if (f.nextLabel(index) == e[1])
183 if (e0 != -1 && e1 != -1)
188 else if (e[1] == pointI)
190 // One of the edges using pointI. Check which one.
191 label index = findIndex(f, pointI);
193 if (f.nextLabel(index) == e[0])
202 if (e0 != -1 && e1 != -1)
209 FatalErrorIn("getPointEdges") << "Cannot find two edges on face:" << faceI
210 << " vertices:" << patch.localFaces()[faceI]
211 << " that uses point:" << pointI
212 << abort(FatalError);
216 // Collect the face on an external point of the patch.
217 Foam::labelList Foam::polyDualMesh::collectPatchSideFace
219 const polyPatch& patch,
220 const label patchToDualOffset,
221 const labelList& edgeToDualPoint,
222 const labelList& pointToDualPoint,
228 // Construct face by walking around e[eI] starting from
231 label meshPointI = patch.meshPoints()[pointI];
232 const labelList& pFaces = patch.pointFaces()[pointI];
234 DynamicList<label> dualFace;
236 if (pointToDualPoint[meshPointI] >= 0)
238 // Number of pFaces + 2 boundary edge + feature point
239 dualFace.setCapacity(pFaces.size()+2+1);
240 // Store dualVertex for feature edge
241 dualFace.append(pointToDualPoint[meshPointI]);
245 dualFace.setCapacity(pFaces.size()+2);
248 // Store dual vertex for starting edge.
249 if (edgeToDualPoint[patch.meshEdges()[edgeI]] < 0)
251 FatalErrorIn("polyDualMesh::collectPatchSideFace") << edgeI
252 << abort(FatalError);
255 dualFace.append(edgeToDualPoint[patch.meshEdges()[edgeI]]);
257 label faceI = patch.edgeFaces()[edgeI][0];
259 // Check order of vertices of edgeI in face to see if we need to reverse.
263 getPointEdges(patch, faceI, pointI, e0, e1);
276 // Store dual vertex for faceI.
277 dualFace.append(faceI + patchToDualOffset);
279 // Cross face to other edge on pointI
281 getPointEdges(patch, faceI, pointI, e0, e1);
292 if (edgeToDualPoint[patch.meshEdges()[edgeI]] >= 0)
294 // Feature edge. Insert dual vertex for edge.
295 dualFace.append(edgeToDualPoint[patch.meshEdges()[edgeI]]);
298 const labelList& eFaces = patch.edgeFaces()[edgeI];
300 if (eFaces.size() == 1)
302 // Reached other edge of patch
306 // Cross edge to other face.
307 if (eFaces[0] == faceI)
328 // Collect face around pointI which is not on the outside of the patch.
329 // Returns the vertices of the face and the indices in these vertices of
330 // any points which are on feature edges.
331 void Foam::polyDualMesh::collectPatchInternalFace
333 const polyPatch& patch,
334 const label patchToDualOffset,
335 const labelList& edgeToDualPoint,
338 const label startEdgeI,
340 labelList& dualFace2,
341 labelList& featEdgeIndices2
344 // Construct face by walking around pointI starting from startEdgeI
345 const labelList& meshEdges = patch.meshEdges();
346 const labelList& pFaces = patch.pointFaces()[pointI];
348 // Vertices of dualFace
349 DynamicList<label> dualFace(pFaces.size());
350 // Indices in dualFace of vertices added because of feature edge
351 DynamicList<label> featEdgeIndices(dualFace.size());
354 label edgeI = startEdgeI;
355 label faceI = patch.edgeFaces()[edgeI][0];
357 // Check order of vertices of edgeI in face to see if we need to reverse.
361 getPointEdges(patch, faceI, pointI, e0, e1);
374 // Insert dual vertex for face
375 dualFace.append(faceI + patchToDualOffset);
377 // Cross face to other edge on pointI
379 getPointEdges(patch, faceI, pointI, e0, e1);
390 if (edgeToDualPoint[meshEdges[edgeI]] >= 0)
392 // Feature edge. Insert dual vertex for edge.
393 dualFace.append(edgeToDualPoint[meshEdges[edgeI]]);
394 featEdgeIndices.append(dualFace.size()-1);
397 if (edgeI == startEdgeI)
402 // Cross edge to other face.
403 const labelList& eFaces = patch.edgeFaces()[edgeI];
405 if (eFaces[0] == faceI)
415 dualFace2.transfer(dualFace);
417 featEdgeIndices2.transfer(featEdgeIndices);
423 // Correct featEdgeIndices for change in dualFace2
424 forAll(featEdgeIndices2, i)
426 featEdgeIndices2[i] = dualFace2.size() -1 - featEdgeIndices2[i];
428 // Reverse indices (might not be nessecary but do anyway)
429 reverse(featEdgeIndices2);
434 void Foam::polyDualMesh::splitFace
436 const polyPatch& patch,
437 const labelList& pointToDualPoint,
440 const labelList& dualFace,
441 const labelList& featEdgeIndices,
443 DynamicList<face>& dualFaces,
444 DynamicList<label>& dualOwner,
445 DynamicList<label>& dualNeighbour,
446 DynamicList<label>& dualRegion
450 // Split face because of feature edges/points
451 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
452 label meshPointI = patch.meshPoints()[pointI];
454 if (pointToDualPoint[meshPointI] >= 0)
456 // Feature point. Do face-centre decomposition.
458 if (featEdgeIndices.size() < 2)
460 // Feature point but no feature edges. Not handled at the moment
461 dualFaces.append(face(dualFace));
462 dualOwner.append(meshPointI);
463 dualNeighbour.append(-1);
464 dualRegion.append(patch.index());
468 // Do 'face-centre' decomposition. Start from first feature
469 // edge create face up until next feature edge.
471 forAll(featEdgeIndices, i)
473 label startFp = featEdgeIndices[i];
475 label endFp = featEdgeIndices[(i+1) % featEdgeIndices.size()];
477 // Collect face from startFp to endFp
482 sz = endFp - startFp + 2;
486 sz = endFp + dualFace.size() - startFp + 2;
490 // feature point becomes face centre.
491 subFace[0] = pointToDualPoint[patch.meshPoints()[pointI]];
493 // Copy from startFp up to endFp.
494 for (label subFp = 1; subFp < subFace.size(); subFp++)
496 subFace[subFp] = dualFace[startFp];
498 startFp = (startFp+1) % dualFace.size();
501 dualFaces.append(face(subFace));
502 dualOwner.append(meshPointI);
503 dualNeighbour.append(-1);
504 dualRegion.append(patch.index());
510 // No feature point. Check if feature edges.
511 if (featEdgeIndices.size() < 2)
513 // Not enough feature edges. No split.
514 dualFaces.append(face(dualFace));
515 dualOwner.append(meshPointI);
516 dualNeighbour.append(-1);
517 dualRegion.append(patch.index());
521 // Multiple feature edges but no feature point.
522 // Split face along feature edges. Gives weird result if
523 // number of feature edges > 2.
525 // Storage for new face
526 DynamicList<label> subFace(dualFace.size());
528 forAll(featEdgeIndices, featI)
530 label startFp = featEdgeIndices[featI];
531 label endFp = featEdgeIndices[featEdgeIndices.fcIndex(featI)];
537 label vertI = dualFace[fp];
539 subFace.append(vertI);
546 fp = dualFace.fcIndex(fp);
549 if (subFace.size() > 2)
551 // Enough vertices to create a face from.
554 dualFaces.append(face(subFace));
555 dualOwner.append(meshPointI);
556 dualNeighbour.append(-1);
557 dualRegion.append(patch.index());
563 if (subFace.size() > 2)
565 // Enough vertices to create a face from.
568 dualFaces.append(face(subFace));
569 dualOwner.append(meshPointI);
570 dualNeighbour.append(-1);
571 dualRegion.append(patch.index());
580 // Create boundary face for every point in patch
581 void Foam::polyDualMesh::dualPatch
583 const polyPatch& patch,
584 const label patchToDualOffset,
585 const labelList& edgeToDualPoint,
586 const labelList& pointToDualPoint,
588 const pointField& dualPoints,
590 DynamicList<face>& dualFaces,
591 DynamicList<label>& dualOwner,
592 DynamicList<label>& dualNeighbour,
593 DynamicList<label>& dualRegion
596 const labelList& meshEdges = patch.meshEdges();
598 // Whether edge has been done.
600 // 1 : done e.start()
603 labelList doneEdgeSide(meshEdges.size(), 0);
605 boolList donePoint(patch.nPoints(), false);
608 // Do points on edge of patch
609 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
611 forAll(doneEdgeSide, patchEdgeI)
613 const labelList& eFaces = patch.edgeFaces()[patchEdgeI];
615 if (eFaces.size() == 1)
617 const edge& e = patch.edges()[patchEdgeI];
621 label bitMask = 1<<eI;
623 if ((doneEdgeSide[patchEdgeI] & bitMask) == 0)
625 // Construct face by walking around e[eI] starting from
628 label pointI = e[eI];
630 label edgeI = patchEdgeI;
645 // Now edgeI is end edge. Mark as visited
646 if (patch.edges()[edgeI][0] == pointI)
648 doneEdgeSide[edgeI] |= 1;
652 doneEdgeSide[edgeI] |= 2;
655 dualFaces.append(face(dualFace));
656 dualOwner.append(patch.meshPoints()[pointI]);
657 dualNeighbour.append(-1);
658 dualRegion.append(patch.index());
660 doneEdgeSide[patchEdgeI] |= bitMask;
661 donePoint[pointI] = true;
669 // Do patch-internal points
670 // ~~~~~~~~~~~~~~~~~~~~~~~~
672 forAll(donePoint, pointI)
674 if (!donePoint[pointI])
676 labelList dualFace, featEdgeIndices;
678 collectPatchInternalFace
684 patch.pointEdges()[pointI][0], // Arbitrary starting edge
690 //- Either keep in one piece or split face according to feature.
692 //// Keep face in one piece.
693 //dualFaces.append(face(dualFace));
694 //dualOwner.append(patch.meshPoints()[pointI]);
695 //dualNeighbour.append(-1);
696 //dualRegion.append(patch.index());
712 donePoint[pointI] = true;
718 void Foam::polyDualMesh::calcDual
720 const polyMesh& mesh,
721 const labelList& featureEdges,
722 const labelList& featurePoints
725 const polyBoundaryMesh& patches = mesh.boundaryMesh();
726 const label nIntFaces = mesh.nInternalFaces();
729 // Get patch for all of outside
730 primitivePatch allBoundary
735 mesh.nFaces() - nIntFaces,
741 // Correspondence from patch edge to mesh edge.
744 allBoundary.meshEdges
752 pointSet nonManifoldPoints
756 meshEdges.size() / 100
759 allBoundary.checkPointManifold(true, &nonManifoldPoints);
761 if (nonManifoldPoints.size())
763 nonManifoldPoints.write();
767 "polyDualMesh::calcDual(const polyMesh&, const labelList&"
768 ", const labelList&)"
769 ) << "There are " << nonManifoldPoints.size() << " points where"
770 << " the outside of the mesh is non-manifold." << nl
771 << "Such a mesh cannot be converted to a dual." << nl
772 << "Writing points at non-manifold sites to pointSet "
773 << nonManifoldPoints.name()
782 // mesh label dualMesh vertex
783 // ---------- ---------------
785 // faceI nCells+faceI-nIntFaces
786 // featEdgeI nCells+nFaces-nIntFaces+featEdgeI
787 // featPointI nCells+nFaces-nIntFaces+nFeatEdges+featPointI
789 pointField dualPoints
791 mesh.nCells() // cell centres
792 + mesh.nFaces() - nIntFaces // boundary face centres
793 + featureEdges.size() // additional boundary edges
794 + featurePoints.size() // additional boundary points
797 label dualPointI = 0;
801 const pointField& cellCentres = mesh.cellCentres();
803 cellPoint_.setSize(cellCentres.size());
805 forAll(cellCentres, cellI)
807 cellPoint_[cellI] = dualPointI;
808 dualPoints[dualPointI++] = cellCentres[cellI];
811 // Boundary faces centres
812 const pointField& faceCentres = mesh.faceCentres();
814 boundaryFacePoint_.setSize(mesh.nFaces() - nIntFaces);
816 for (label faceI = nIntFaces; faceI < mesh.nFaces(); faceI++)
818 boundaryFacePoint_[faceI - nIntFaces] = dualPointI;
819 dualPoints[dualPointI++] = faceCentres[faceI];
823 // >0 : dual point label (edge is feature edge)
824 // -1 : is boundary edge.
825 // -2 : is internal edge.
826 labelList edgeToDualPoint(mesh.nEdges(), -2);
828 forAll(meshEdges, patchEdgeI)
830 label edgeI = meshEdges[patchEdgeI];
832 edgeToDualPoint[edgeI] = -1;
835 forAll(featureEdges, i)
837 label edgeI = featureEdges[i];
839 const edge& e = mesh.edges()[edgeI];
841 edgeToDualPoint[edgeI] = dualPointI;
842 dualPoints[dualPointI++] = e.centre(mesh.points());
848 // >0 : dual point label (point is feature point)
849 // -1 : is point on edge of patch
850 // -2 : is point on patch (but not on edge)
851 // -3 : is internal point.
852 labelList pointToDualPoint(mesh.nPoints(), -3);
854 forAll(patches, patchI)
856 const labelList& meshPoints = patches[patchI].meshPoints();
858 forAll(meshPoints, i)
860 pointToDualPoint[meshPoints[i]] = -2;
863 const labelListList& loops = patches[patchI].edgeLoops();
867 const labelList& loop = loops[i];
871 pointToDualPoint[meshPoints[loop[j]]] = -1;
876 forAll(featurePoints, i)
878 label pointI = featurePoints[i];
880 pointToDualPoint[pointI] = dualPointI;
881 dualPoints[dualPointI++] = mesh.points()[pointI];
885 // Storage for new faces.
886 // Dynamic sized since we don't know size.
888 DynamicList<face> dynDualFaces(mesh.nEdges());
889 DynamicList<label> dynDualOwner(mesh.nEdges());
890 DynamicList<label> dynDualNeighbour(mesh.nEdges());
891 DynamicList<label> dynDualRegion(mesh.nEdges());
894 // Generate faces from edges on the boundary
895 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
897 forAll(meshEdges, patchEdgeI)
899 label edgeI = meshEdges[patchEdgeI];
901 const edge& e = mesh.edges()[edgeI];
904 label neighbour = -1;
917 // Find the boundary faces using the edge.
918 const labelList& patchFaces = allBoundary.edgeFaces()[patchEdgeI];
920 if (patchFaces.size() != 2)
922 FatalErrorIn("polyDualMesh::calcDual")
923 << "Cannot handle edges with " << patchFaces.size()
924 << " connected boundary faces."
925 << abort(FatalError);
928 label face0 = patchFaces[0] + nIntFaces;
929 const face& f0 = mesh.faces()[face0];
931 label face1 = patchFaces[1] + nIntFaces;
933 // We want to start walking from patchFaces[0] or patchFaces[1],
934 // depending on which one uses owner,neighbour in the right order.
936 label startFaceI = -1;
939 label index = findIndex(f0, neighbour);
941 if (f0.nextLabel(index) == owner)
952 // Now walk from startFaceI to cell to face to cell etc. until endFaceI
954 DynamicList<label> dualFace;
956 if (edgeToDualPoint[edgeI] >= 0)
958 // Number of cells + 2 boundary faces + feature edge point
959 dualFace.setCapacity(mesh.edgeCells()[edgeI].size()+2+1);
960 // Store dualVertex for feature edge
961 dualFace.append(edgeToDualPoint[edgeI]);
965 dualFace.setCapacity(mesh.edgeCells()[edgeI].size()+2);
968 // Store dual vertex for starting face.
969 dualFace.append(mesh.nCells() + startFaceI - nIntFaces);
971 label cellI = mesh.faceOwner()[startFaceI];
972 label faceI = startFaceI;
976 // Store dual vertex from cellI.
977 dualFace.append(cellI);
979 // Cross cell to other face on edge.
981 meshTools::getEdgeFaces(mesh, cellI, edgeI, f0, f1);
992 // Cross face to other cell.
993 if (faceI == endFaceI)
998 if (mesh.faceOwner()[faceI] == cellI)
1000 cellI = mesh.faceNeighbour()[faceI];
1004 cellI = mesh.faceOwner()[faceI];
1008 // Store dual vertex for endFace.
1009 dualFace.append(mesh.nCells() + endFaceI - nIntFaces);
1011 dynDualFaces.append(face(dualFace.shrink()));
1012 dynDualOwner.append(owner);
1013 dynDualNeighbour.append(neighbour);
1014 dynDualRegion.append(-1);
1017 // Check orientation.
1018 const face& f = dynDualFaces[dynDualFaces.size()-1];
1019 vector n = f.normal(dualPoints);
1020 if (((mesh.points()[owner] - dualPoints[f[0]]) & n) > 0)
1022 WarningIn("calcDual") << "Incorrect orientation"
1023 << " on boundary edge:" << edgeI
1024 << mesh.points()[mesh.edges()[edgeI][0]]
1025 << mesh.points()[mesh.edges()[edgeI][1]]
1032 // Generate faces from internal edges
1033 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1035 forAll(edgeToDualPoint, edgeI)
1037 if (edgeToDualPoint[edgeI] == -2)
1041 // Find dual owner, neighbour
1043 const edge& e = mesh.edges()[edgeI];
1046 label neighbour = -1;
1059 // Get a starting cell
1060 const labelList& eCells = mesh.edgeCells()[edgeI];
1062 label cellI = eCells[0];
1064 // Get the two faces on the cell and edge.
1066 meshTools::getEdgeFaces(mesh, cellI, edgeI, face0, face1);
1068 // Find the starting face by looking at the order in which
1069 // the face uses the owner, neighbour
1070 const face& f0 = mesh.faces()[face0];
1072 label index = findIndex(f0, neighbour);
1074 bool f0OrderOk = (f0.nextLabel(index) == owner);
1076 label startFaceI = -1;
1078 if (f0OrderOk == (mesh.faceOwner()[face0] == cellI))
1087 // Walk face-cell-face until starting face reached.
1088 DynamicList<label> dualFace(mesh.edgeCells()[edgeI].size());
1090 label faceI = startFaceI;
1094 // Store dual vertex from cellI.
1095 dualFace.append(cellI);
1097 // Cross cell to other face on edge.
1099 meshTools::getEdgeFaces(mesh, cellI, edgeI, f0, f1);
1110 // Cross face to other cell.
1111 if (faceI == startFaceI)
1116 if (mesh.faceOwner()[faceI] == cellI)
1118 cellI = mesh.faceNeighbour()[faceI];
1122 cellI = mesh.faceOwner()[faceI];
1126 dynDualFaces.append(face(dualFace.shrink()));
1127 dynDualOwner.append(owner);
1128 dynDualNeighbour.append(neighbour);
1129 dynDualRegion.append(-1);
1132 // Check orientation.
1133 const face& f = dynDualFaces[dynDualFaces.size()-1];
1134 vector n = f.normal(dualPoints);
1135 if (((mesh.points()[owner] - dualPoints[f[0]]) & n) > 0)
1137 WarningIn("calcDual") << "Incorrect orientation"
1138 << " on internal edge:" << edgeI
1139 << mesh.points()[mesh.edges()[edgeI][0]]
1140 << mesh.points()[mesh.edges()[edgeI][1]]
1150 dynDualFaces.shrink();
1151 dynDualOwner.shrink();
1152 dynDualNeighbour.shrink();
1153 dynDualRegion.shrink();
1155 OFstream str("dualInternalFaces.obj");
1156 Pout<< "polyDualMesh::calcDual : dumping internal faces to "
1157 << str.name() << endl;
1159 forAll(dualPoints, dualPointI)
1161 meshTools::writeOBJ(str, dualPoints[dualPointI]);
1163 forAll(dynDualFaces, dualFaceI)
1165 const face& f = dynDualFaces[dualFaceI];
1170 str<< ' ' << f[fp]+1;
1176 const label nInternalFaces = dynDualFaces.size();
1181 forAll(patches, patchI)
1183 const polyPatch& pp = patches[patchI];
1188 mesh.nCells() + pp.start() - nIntFaces,
1202 // Transfer face info to straight lists
1203 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1204 faceList dualFaces(dynDualFaces.shrink(), true);
1205 dynDualFaces.clear();
1207 labelList dualOwner(dynDualOwner.shrink(), true);
1208 dynDualOwner.clear();
1210 labelList dualNeighbour(dynDualNeighbour.shrink(), true);
1211 dynDualNeighbour.clear();
1213 labelList dualRegion(dynDualRegion.shrink(), true);
1214 dynDualRegion.clear();
1221 OFstream str("dualFaces.obj");
1222 Pout<< "polyDualMesh::calcDual : dumping all faces to "
1223 << str.name() << endl;
1225 forAll(dualPoints, dualPointI)
1227 meshTools::writeOBJ(str, dualPoints[dualPointI]);
1229 forAll(dualFaces, dualFaceI)
1231 const face& f = dualFaces[dualFaceI];
1236 str<< ' ' << f[fp]+1;
1243 cellList dualCells(mesh.nPoints());
1245 forAll(dualCells, cellI)
1247 dualCells[cellI].setSize(0);
1250 forAll(dualOwner, faceI)
1252 label cellI = dualOwner[faceI];
1254 labelList& cFaces = dualCells[cellI];
1256 label sz = cFaces.size();
1257 cFaces.setSize(sz+1);
1260 forAll(dualNeighbour, faceI)
1262 label cellI = dualNeighbour[faceI];
1266 labelList& cFaces = dualCells[cellI];
1268 label sz = cFaces.size();
1269 cFaces.setSize(sz+1);
1275 // Do upper-triangular face ordering. Determines face reordering map and
1276 // number of internal faces.
1291 inplaceReorder(oldToNew, dualFaces);
1292 inplaceReorder(oldToNew, dualOwner);
1293 inplaceReorder(oldToNew, dualNeighbour);
1294 inplaceReorder(oldToNew, dualRegion);
1295 forAll(dualCells, cellI)
1297 inplaceRenumber(oldToNew, dualCells[cellI]);
1302 labelList patchSizes(patches.size(), 0);
1304 forAll(dualRegion, faceI)
1306 if (dualRegion[faceI] >= 0)
1308 patchSizes[dualRegion[faceI]]++;
1312 labelList patchStarts(patches.size(), 0);
1314 label faceI = nInternalFaces;
1316 forAll(patches, patchI)
1318 patchStarts[patchI] = faceI;
1320 faceI += patchSizes[patchI];
1324 Pout<< "nFaces:" << dualFaces.size()
1325 << " patchSizes:" << patchSizes
1326 << " patchStarts:" << patchStarts
1330 // Add patches. First add zero sized (since mesh still 0 size)
1331 List<polyPatch*> dualPatches(patches.size());
1333 forAll(patches, patchI)
1335 const polyPatch& pp = patches[patchI];
1337 dualPatches[patchI] = pp.clone
1341 0, //patchSizes[patchI],
1342 0 //patchStarts[patchI]
1345 addPatches(dualPatches);
1350 xferMove(dualPoints),
1351 xferMove(dualFaces),
1352 xferMove(dualOwner),
1353 xferMove(dualNeighbour),
1360 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1362 // Construct from components
1363 Foam::polyDualMesh::polyDualMesh(const IOobject& io)
1371 time().findInstance(meshDir(), "cellPoint"),
1374 IOobject::MUST_READ,
1382 "boundaryFacePoint",
1383 time().findInstance(meshDir(), "boundaryFacePoint"),
1386 IOobject::MUST_READ,
1393 // Construct from polyMesh
1394 Foam::polyDualMesh::polyDualMesh
1396 const polyMesh& mesh,
1397 const labelList& featureEdges,
1398 const labelList& featurePoints
1404 xferCopy(pointField()), // to prevent any warnings "points not allocated"
1405 xferCopy(faceList()), // to prevent any warnings "faces not allocated"
1406 xferCopy(cellList())
1413 time().findInstance(meshDir(), "faces"),
1417 IOobject::AUTO_WRITE
1419 labelList(mesh.nCells(), -1)
1425 "boundaryFacePoint",
1426 time().findInstance(meshDir(), "faces"),
1430 IOobject::AUTO_WRITE
1432 labelList(mesh.nFaces() - mesh.nInternalFaces())
1435 calcDual(mesh, featureEdges, featurePoints);
1439 // Construct from polyMesh and feature angle
1440 Foam::polyDualMesh::polyDualMesh
1442 const polyMesh& mesh,
1443 const scalar featureCos
1449 xferCopy(pointField()), // to prevent any warnings "points not allocated"
1450 xferCopy(faceList()), // to prevent any warnings "faces not allocated"
1451 xferCopy(cellList())
1458 time().findInstance(meshDir(), "faces"),
1462 IOobject::AUTO_WRITE
1464 labelList(mesh.nCells(), -1)
1470 "boundaryFacePoint",
1471 time().findInstance(meshDir(), "faces"),
1475 IOobject::AUTO_WRITE
1477 labelList(mesh.nFaces() - mesh.nInternalFaces(), -1)
1480 labelList featureEdges, featurePoints;
1482 calcFeatures(mesh, featureCos, featureEdges, featurePoints);
1483 calcDual(mesh, featureEdges, featurePoints);
1487 void Foam::polyDualMesh::calcFeatures
1489 const polyMesh& mesh,
1490 const scalar featureCos,
1491 labelList& featureEdges,
1492 labelList& featurePoints
1495 // Create big primitivePatch for all outside.
1496 primitivePatch allBoundary
1501 mesh.nFaces() - mesh.nInternalFaces(),
1502 mesh.nInternalFaces()
1507 // For ease of use store patch number per face in allBoundary.
1508 labelList allRegion(allBoundary.size());
1510 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1512 forAll(patches, patchI)
1514 const polyPatch& pp = patches[patchI];
1518 allRegion[i + pp.start() - mesh.nInternalFaces()] = patchI;
1523 // Calculate patch/feature edges
1524 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1526 const labelListList& edgeFaces = allBoundary.edgeFaces();
1527 const vectorField& faceNormals = allBoundary.faceNormals();
1528 const labelList& meshPoints = allBoundary.meshPoints();
1530 boolList isFeatureEdge(edgeFaces.size(), false);
1532 forAll(edgeFaces, edgeI)
1534 const labelList& eFaces = edgeFaces[edgeI];
1536 if (eFaces.size() != 2)
1538 // Non-manifold. Problem?
1539 const edge& e = allBoundary.edges()[edgeI];
1541 WarningIn("polyDualMesh::calcFeatures") << "Edge "
1542 << meshPoints[e[0]] << ' ' << meshPoints[e[1]]
1543 << " coords:" << mesh.points()[meshPoints[e[0]]]
1544 << mesh.points()[meshPoints[e[1]]]
1545 << " has more than 2 faces connected to it:"
1546 << eFaces.size() << endl;
1548 isFeatureEdge[edgeI] = true;
1550 else if (allRegion[eFaces[0]] != allRegion[eFaces[1]])
1552 isFeatureEdge[edgeI] = true;
1556 (faceNormals[eFaces[0]] & faceNormals[eFaces[1]])
1560 isFeatureEdge[edgeI] = true;
1565 // Calculate feature points
1566 // ~~~~~~~~~~~~~~~~~~~~~~~~
1568 const labelListList& pointEdges = allBoundary.pointEdges();
1570 DynamicList<label> allFeaturePoints(pointEdges.size());
1572 forAll(pointEdges, pointI)
1574 const labelList& pEdges = pointEdges[pointI];
1576 label nFeatEdges = 0;
1580 if (isFeatureEdge[pEdges[i]])
1587 // Store in mesh vertex label
1588 allFeaturePoints.append(allBoundary.meshPoints()[pointI]);
1591 featurePoints.transfer(allFeaturePoints);
1595 OFstream str("featurePoints.obj");
1597 Pout<< "polyDualMesh::calcFeatures : dumping feature points to "
1598 << str.name() << endl;
1600 forAll(featurePoints, i)
1602 label pointI = featurePoints[i];
1603 meshTools::writeOBJ(str, mesh.points()[pointI]);
1608 // Get all feature edges.
1611 allBoundary.meshEdges
1619 mesh.nInternalFaces()
1624 DynamicList<label> allFeatureEdges(isFeatureEdge.size());
1625 forAll(isFeatureEdge, edgeI)
1627 if (isFeatureEdge[edgeI])
1629 // Store in mesh edge label.
1630 allFeatureEdges.append(meshEdges[edgeI]);
1633 featureEdges.transfer(allFeatureEdges);
1637 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1639 Foam::polyDualMesh::~polyDualMesh()
1643 // ************************************************************************* //