1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
27 \*---------------------------------------------------------------------------*/
29 #include "polyDualMesh.H"
30 #include "meshTools.H"
33 #include "SortableList.H"
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 defineTypeNameAndDebug(polyDualMesh, 0);
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 // Determine order for faces:
46 // - upper-triangular order for internal faces
47 // - external faces after internal faces (were already so)
48 Foam::labelList Foam::polyDualMesh::getFaceOrder
50 const labelList& faceOwner,
51 const labelList& faceNeighbour,
52 const cellList& cells,
56 labelList oldToNew(faceOwner.size(), -1);
58 // First unassigned face
63 const labelList& cFaces = cells[cellI];
65 SortableList<label> nbr(cFaces.size());
69 label faceI = cFaces[i];
71 label nbrCellI = faceNeighbour[faceI];
75 // Internal face. Get cell on other side.
76 if (nbrCellI == cellI)
78 nbrCellI = faceOwner[faceI];
88 // nbrCell is master. Let it handle this face.
94 // External face. Do later.
105 oldToNew[cFaces[nbr.indices()[i]]] = newFaceI++;
110 nInternalFaces = newFaceI;
112 Pout<< "nInternalFaces:" << nInternalFaces << endl;
113 Pout<< "nFaces:" << faceOwner.size() << endl;
114 Pout<< "nCells:" << cells.size() << endl;
116 // Leave patch faces intact.
117 for (label faceI = newFaceI; faceI < faceOwner.size(); faceI++)
119 oldToNew[faceI] = faceI;
123 // Check done all faces.
124 forAll(oldToNew, faceI)
126 if (oldToNew[faceI] == -1)
130 "polyDualMesh::getFaceOrder"
131 "(const labelList&, const labelList&, const label) const"
132 ) << "Did not determine new position"
133 << " for face " << faceI
134 << abort(FatalError);
142 // Get the two edges on faceI using pointI. Returns them such that the order
143 // - otherVertex of e0
145 // - otherVertex(pointI) of e1
147 void Foam::polyDualMesh::getPointEdges
149 const primitivePatch& patch,
156 const labelList& fEdges = patch.faceEdges()[faceI];
157 const face& f = patch.localFaces()[faceI];
164 label edgeI = fEdges[i];
166 const edge& e = patch.edges()[edgeI];
170 // One of the edges using pointI. Check which one.
171 label index = findIndex(f, pointI);
173 if (f.nextLabel(index) == e[1])
182 if (e0 != -1 && e1 != -1)
187 else if (e[1] == pointI)
189 // One of the edges using pointI. Check which one.
190 label index = findIndex(f, pointI);
192 if (f.nextLabel(index) == e[0])
201 if (e0 != -1 && e1 != -1)
208 FatalErrorIn("getPointEdges") << "Cannot find two edges on face:" << faceI
209 << " vertices:" << patch.localFaces()[faceI]
210 << " that uses point:" << pointI
211 << abort(FatalError);
215 // Collect the face on an external point of the patch.
216 Foam::labelList Foam::polyDualMesh::collectPatchSideFace
218 const polyPatch& patch,
219 const label patchToDualOffset,
220 const labelList& edgeToDualPoint,
221 const labelList& pointToDualPoint,
227 // Construct face by walking around e[eI] starting from
230 label meshPointI = patch.meshPoints()[pointI];
231 const labelList& pFaces = patch.pointFaces()[pointI];
233 dynamicLabelList dualFace;
235 if (pointToDualPoint[meshPointI] >= 0)
237 // Number of pFaces + 2 boundary edge + feature point
238 dualFace.setCapacity(pFaces.size()+2+1);
239 // Store dualVertex for feature edge
240 dualFace.append(pointToDualPoint[meshPointI]);
244 dualFace.setCapacity(pFaces.size()+2);
247 // Store dual vertex for starting edge.
248 if (edgeToDualPoint[patch.meshEdges()[edgeI]] < 0)
250 FatalErrorIn("polyDualMesh::collectPatchSideFace") << edgeI
251 << abort(FatalError);
254 dualFace.append(edgeToDualPoint[patch.meshEdges()[edgeI]]);
256 label faceI = patch.edgeFaces()[edgeI][0];
258 // Check order of vertices of edgeI in face to see if we need to reverse.
262 getPointEdges(patch, faceI, pointI, e0, e1);
275 // Store dual vertex for faceI.
276 dualFace.append(faceI + patchToDualOffset);
278 // Cross face to other edge on pointI
280 getPointEdges(patch, faceI, pointI, e0, e1);
291 if (edgeToDualPoint[patch.meshEdges()[edgeI]] >= 0)
293 // Feature edge. Insert dual vertex for edge.
294 dualFace.append(edgeToDualPoint[patch.meshEdges()[edgeI]]);
297 const labelList& eFaces = patch.edgeFaces()[edgeI];
299 if (eFaces.size() == 1)
301 // Reached other edge of patch
305 // Cross edge to other face.
306 if (eFaces[0] == faceI)
327 // Collect face around pointI which is not on the outside of the patch.
328 // Returns the vertices of the face and the indices in these vertices of
329 // any points which are on feature edges.
330 void Foam::polyDualMesh::collectPatchInternalFace
332 const polyPatch& patch,
333 const label patchToDualOffset,
334 const labelList& edgeToDualPoint,
337 const label startEdgeI,
339 labelList& dualFace2,
340 labelList& featEdgeIndices2
343 // Construct face by walking around pointI starting from startEdgeI
344 const labelList& meshEdges = patch.meshEdges();
345 const labelList& pFaces = patch.pointFaces()[pointI];
347 // Vertices of dualFace
348 dynamicLabelList dualFace(pFaces.size());
349 // Indices in dualFace of vertices added because of feature edge
350 dynamicLabelList featEdgeIndices(dualFace.size());
353 label edgeI = startEdgeI;
354 label faceI = patch.edgeFaces()[edgeI][0];
356 // Check order of vertices of edgeI in face to see if we need to reverse.
360 getPointEdges(patch, faceI, pointI, e0, e1);
373 // Insert dual vertex for face
374 dualFace.append(faceI + patchToDualOffset);
376 // Cross face to other edge on pointI
378 getPointEdges(patch, faceI, pointI, e0, e1);
389 if (edgeToDualPoint[meshEdges[edgeI]] >= 0)
391 // Feature edge. Insert dual vertex for edge.
392 dualFace.append(edgeToDualPoint[meshEdges[edgeI]]);
393 featEdgeIndices.append(dualFace.size()-1);
396 if (edgeI == startEdgeI)
401 // Cross edge to other face.
402 const labelList& eFaces = patch.edgeFaces()[edgeI];
404 if (eFaces[0] == faceI)
414 dualFace2.transfer(dualFace);
416 featEdgeIndices2.transfer(featEdgeIndices);
422 // Correct featEdgeIndices for change in dualFace2
423 forAll(featEdgeIndices2, i)
425 featEdgeIndices2[i] = dualFace2.size() -1 - featEdgeIndices2[i];
427 // Reverse indices (might not be nessecary but do anyway)
428 reverse(featEdgeIndices2);
433 void Foam::polyDualMesh::splitFace
435 const polyPatch& patch,
436 const labelList& pointToDualPoint,
439 const labelList& dualFace,
440 const labelList& featEdgeIndices,
442 DynamicList<face>& dualFaces,
443 dynamicLabelList& dualOwner,
444 dynamicLabelList& dualNeighbour,
445 dynamicLabelList& dualRegion
449 // Split face because of feature edges/points
450 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
451 label meshPointI = patch.meshPoints()[pointI];
453 if (pointToDualPoint[meshPointI] >= 0)
455 // Feature point. Do face-centre decomposition.
457 if (featEdgeIndices.size() < 2)
459 // Feature point but no feature edges. Not handled at the moment
460 dualFaces.append(face(dualFace));
461 dualOwner.append(meshPointI);
462 dualNeighbour.append(-1);
463 dualRegion.append(patch.index());
467 // Do 'face-centre' decomposition. Start from first feature
468 // edge create face up until next feature edge.
470 forAll(featEdgeIndices, i)
472 label startFp = featEdgeIndices[i];
474 label endFp = featEdgeIndices[(i+1) % featEdgeIndices.size()];
476 // Collect face from startFp to endFp
481 sz = endFp - startFp + 2;
485 sz = endFp + dualFace.size() - startFp + 2;
489 // feature point becomes face centre.
490 subFace[0] = pointToDualPoint[patch.meshPoints()[pointI]];
492 // Copy from startFp up to endFp.
493 for (label subFp = 1; subFp < subFace.size(); subFp++)
495 subFace[subFp] = dualFace[startFp];
497 startFp = (startFp+1) % dualFace.size();
500 dualFaces.append(face(subFace));
501 dualOwner.append(meshPointI);
502 dualNeighbour.append(-1);
503 dualRegion.append(patch.index());
509 // No feature point. Check if feature edges.
510 if (featEdgeIndices.size() < 2)
512 // Not enough feature edges. No split.
513 dualFaces.append(face(dualFace));
514 dualOwner.append(meshPointI);
515 dualNeighbour.append(-1);
516 dualRegion.append(patch.index());
520 // Multiple feature edges but no feature point.
521 // Split face along feature edges. Gives weird result if
522 // number of feature edges > 2.
524 // Storage for new face
525 dynamicLabelList subFace(dualFace.size());
527 forAll(featEdgeIndices, featI)
529 label startFp = featEdgeIndices[featI];
530 label endFp = featEdgeIndices[featEdgeIndices.fcIndex(featI)];
536 label vertI = dualFace[fp];
538 subFace.append(vertI);
545 fp = dualFace.fcIndex(fp);
548 if (subFace.size() > 2)
550 // Enough vertices to create a face from.
553 dualFaces.append(face(subFace));
554 dualOwner.append(meshPointI);
555 dualNeighbour.append(-1);
556 dualRegion.append(patch.index());
562 if (subFace.size() > 2)
564 // Enough vertices to create a face from.
567 dualFaces.append(face(subFace));
568 dualOwner.append(meshPointI);
569 dualNeighbour.append(-1);
570 dualRegion.append(patch.index());
579 // Create boundary face for every point in patch
580 void Foam::polyDualMesh::dualPatch
582 const polyPatch& patch,
583 const label patchToDualOffset,
584 const labelList& edgeToDualPoint,
585 const labelList& pointToDualPoint,
587 const pointField& dualPoints,
589 DynamicList<face>& dualFaces,
590 dynamicLabelList& dualOwner,
591 dynamicLabelList& dualNeighbour,
592 dynamicLabelList& dualRegion
595 const labelList& meshEdges = patch.meshEdges();
597 // Whether edge has been done.
599 // 1 : done e.start()
602 labelList doneEdgeSide(meshEdges.size(), 0);
604 boolList donePoint(patch.nPoints(), false);
607 // Do points on edge of patch
608 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
610 forAll(doneEdgeSide, patchEdgeI)
612 const labelList& eFaces = patch.edgeFaces()[patchEdgeI];
614 if (eFaces.size() == 1)
616 const edge& e = patch.edges()[patchEdgeI];
620 label bitMask = 1<<eI;
622 if ((doneEdgeSide[patchEdgeI] & bitMask) == 0)
624 // Construct face by walking around e[eI] starting from
627 label pointI = e[eI];
629 label edgeI = patchEdgeI;
644 // Now edgeI is end edge. Mark as visited
645 if (patch.edges()[edgeI][0] == pointI)
647 doneEdgeSide[edgeI] |= 1;
651 doneEdgeSide[edgeI] |= 2;
654 dualFaces.append(face(dualFace));
655 dualOwner.append(patch.meshPoints()[pointI]);
656 dualNeighbour.append(-1);
657 dualRegion.append(patch.index());
659 doneEdgeSide[patchEdgeI] |= bitMask;
660 donePoint[pointI] = true;
668 // Do patch-internal points
669 // ~~~~~~~~~~~~~~~~~~~~~~~~
671 forAll(donePoint, pointI)
673 if (!donePoint[pointI])
675 labelList dualFace, featEdgeIndices;
677 collectPatchInternalFace
683 patch.pointEdges()[pointI][0], // Arbitrary starting edge
689 //- Either keep in one piece or split face according to feature.
691 //// Keep face in one piece.
692 //dualFaces.append(face(dualFace));
693 //dualOwner.append(patch.meshPoints()[pointI]);
694 //dualNeighbour.append(-1);
695 //dualRegion.append(patch.index());
711 donePoint[pointI] = true;
717 void Foam::polyDualMesh::calcDual
719 const polyMesh& mesh,
720 const labelList& featureEdges,
721 const labelList& featurePoints
724 const polyBoundaryMesh& patches = mesh.boundaryMesh();
725 const label nIntFaces = mesh.nInternalFaces();
728 // Get patch for all of outside
729 primitivePatch allBoundary
734 mesh.nFaces() - nIntFaces,
740 // Correspondence from patch edge to mesh edge.
743 allBoundary.meshEdges
751 pointSet nonManifoldPoints
755 meshEdges.size() / 100
758 allBoundary.checkPointManifold(true, &nonManifoldPoints);
760 if (nonManifoldPoints.size())
762 nonManifoldPoints.write();
766 "polyDualMesh::calcDual(const polyMesh&, const labelList&"
767 ", const labelList&)"
768 ) << "There are " << nonManifoldPoints.size() << " points where"
769 << " the outside of the mesh is non-manifold." << nl
770 << "Such a mesh cannot be converted to a dual." << nl
771 << "Writing points at non-manifold sites to pointSet "
772 << nonManifoldPoints.name()
781 // mesh label dualMesh vertex
782 // ---------- ---------------
784 // faceI nCells+faceI-nIntFaces
785 // featEdgeI nCells+nFaces-nIntFaces+featEdgeI
786 // featPointI nCells+nFaces-nIntFaces+nFeatEdges+featPointI
788 pointField dualPoints
790 mesh.nCells() // cell centres
791 + mesh.nFaces() - nIntFaces // boundary face centres
792 + featureEdges.size() // additional boundary edges
793 + featurePoints.size() // additional boundary points
796 label dualPointI = 0;
800 const pointField& cellCentres = mesh.cellCentres();
802 cellPoint_.setSize(cellCentres.size());
804 forAll(cellCentres, cellI)
806 cellPoint_[cellI] = dualPointI;
807 dualPoints[dualPointI++] = cellCentres[cellI];
810 // Boundary faces centres
811 const pointField& faceCentres = mesh.faceCentres();
813 boundaryFacePoint_.setSize(mesh.nFaces() - nIntFaces);
815 for (label faceI = nIntFaces; faceI < mesh.nFaces(); faceI++)
817 boundaryFacePoint_[faceI - nIntFaces] = dualPointI;
818 dualPoints[dualPointI++] = faceCentres[faceI];
822 // >0 : dual point label (edge is feature edge)
823 // -1 : is boundary edge.
824 // -2 : is internal edge.
825 labelList edgeToDualPoint(mesh.nEdges(), -2);
827 forAll(meshEdges, patchEdgeI)
829 label edgeI = meshEdges[patchEdgeI];
831 edgeToDualPoint[edgeI] = -1;
834 forAll(featureEdges, i)
836 label edgeI = featureEdges[i];
838 const edge& e = mesh.edges()[edgeI];
840 edgeToDualPoint[edgeI] = dualPointI;
841 dualPoints[dualPointI++] = e.centre(mesh.points());
847 // >0 : dual point label (point is feature point)
848 // -1 : is point on edge of patch
849 // -2 : is point on patch (but not on edge)
850 // -3 : is internal point.
851 labelList pointToDualPoint(mesh.nPoints(), -3);
853 forAll(patches, patchI)
855 const labelList& meshPoints = patches[patchI].meshPoints();
857 forAll(meshPoints, i)
859 pointToDualPoint[meshPoints[i]] = -2;
862 const labelListList& loops = patches[patchI].edgeLoops();
866 const labelList& loop = loops[i];
870 pointToDualPoint[meshPoints[loop[j]]] = -1;
875 forAll(featurePoints, i)
877 label pointI = featurePoints[i];
879 pointToDualPoint[pointI] = dualPointI;
880 dualPoints[dualPointI++] = mesh.points()[pointI];
884 // Storage for new faces.
885 // Dynamic sized since we don't know size.
887 DynamicList<face> dynDualFaces(mesh.nEdges());
888 dynamicLabelList dynDualOwner(mesh.nEdges());
889 dynamicLabelList dynDualNeighbour(mesh.nEdges());
890 dynamicLabelList dynDualRegion(mesh.nEdges());
893 // Generate faces from edges on the boundary
894 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
896 forAll(meshEdges, patchEdgeI)
898 label edgeI = meshEdges[patchEdgeI];
900 const edge& e = mesh.edges()[edgeI];
903 label neighbour = -1;
916 // Find the boundary faces using the edge.
917 const labelList& patchFaces = allBoundary.edgeFaces()[patchEdgeI];
919 if (patchFaces.size() != 2)
921 FatalErrorIn("polyDualMesh::calcDual")
922 << "Cannot handle edges with " << patchFaces.size()
923 << " connected boundary faces."
924 << abort(FatalError);
927 label face0 = patchFaces[0] + nIntFaces;
928 const face& f0 = mesh.faces()[face0];
930 label face1 = patchFaces[1] + nIntFaces;
932 // We want to start walking from patchFaces[0] or patchFaces[1],
933 // depending on which one uses owner,neighbour in the right order.
935 label startFaceI = -1;
938 label index = findIndex(f0, neighbour);
940 if (f0.nextLabel(index) == owner)
951 // Now walk from startFaceI to cell to face to cell etc. until endFaceI
953 dynamicLabelList dualFace;
955 if (edgeToDualPoint[edgeI] >= 0)
957 // Number of cells + 2 boundary faces + feature edge point
958 dualFace.setCapacity(mesh.edgeCells()[edgeI].size()+2+1);
959 // Store dualVertex for feature edge
960 dualFace.append(edgeToDualPoint[edgeI]);
964 dualFace.setCapacity(mesh.edgeCells()[edgeI].size()+2);
967 // Store dual vertex for starting face.
968 dualFace.append(mesh.nCells() + startFaceI - nIntFaces);
970 label cellI = mesh.faceOwner()[startFaceI];
971 label faceI = startFaceI;
975 // Store dual vertex from cellI.
976 dualFace.append(cellI);
978 // Cross cell to other face on edge.
980 meshTools::getEdgeFaces(mesh, cellI, edgeI, f0, f1);
991 // Cross face to other cell.
992 if (faceI == endFaceI)
997 if (mesh.faceOwner()[faceI] == cellI)
999 cellI = mesh.faceNeighbour()[faceI];
1003 cellI = mesh.faceOwner()[faceI];
1007 // Store dual vertex for endFace.
1008 dualFace.append(mesh.nCells() + endFaceI - nIntFaces);
1010 dynDualFaces.append(face(dualFace.shrink()));
1011 dynDualOwner.append(owner);
1012 dynDualNeighbour.append(neighbour);
1013 dynDualRegion.append(-1);
1016 // Check orientation.
1017 const face& f = dynDualFaces[dynDualFaces.size()-1];
1018 vector n = f.normal(dualPoints);
1019 if (((mesh.points()[owner] - dualPoints[f[0]]) & n) > 0)
1021 WarningIn("calcDual") << "Incorrect orientation"
1022 << " on boundary edge:" << edgeI
1023 << mesh.points()[mesh.edges()[edgeI][0]]
1024 << mesh.points()[mesh.edges()[edgeI][1]]
1031 // Generate faces from internal edges
1032 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1034 forAll(edgeToDualPoint, edgeI)
1036 if (edgeToDualPoint[edgeI] == -2)
1040 // Find dual owner, neighbour
1042 const edge& e = mesh.edges()[edgeI];
1045 label neighbour = -1;
1058 // Get a starting cell
1059 const labelList& eCells = mesh.edgeCells()[edgeI];
1061 label cellI = eCells[0];
1063 // Get the two faces on the cell and edge.
1065 meshTools::getEdgeFaces(mesh, cellI, edgeI, face0, face1);
1067 // Find the starting face by looking at the order in which
1068 // the face uses the owner, neighbour
1069 const face& f0 = mesh.faces()[face0];
1071 label index = findIndex(f0, neighbour);
1073 bool f0OrderOk = (f0.nextLabel(index) == owner);
1075 label startFaceI = -1;
1077 if (f0OrderOk == (mesh.faceOwner()[face0] == cellI))
1086 // Walk face-cell-face until starting face reached.
1087 dynamicLabelList dualFace(mesh.edgeCells()[edgeI].size());
1089 label faceI = startFaceI;
1093 // Store dual vertex from cellI.
1094 dualFace.append(cellI);
1096 // Cross cell to other face on edge.
1098 meshTools::getEdgeFaces(mesh, cellI, edgeI, f0, f1);
1109 // Cross face to other cell.
1110 if (faceI == startFaceI)
1115 if (mesh.faceOwner()[faceI] == cellI)
1117 cellI = mesh.faceNeighbour()[faceI];
1121 cellI = mesh.faceOwner()[faceI];
1125 dynDualFaces.append(face(dualFace.shrink()));
1126 dynDualOwner.append(owner);
1127 dynDualNeighbour.append(neighbour);
1128 dynDualRegion.append(-1);
1131 // Check orientation.
1132 const face& f = dynDualFaces[dynDualFaces.size()-1];
1133 vector n = f.normal(dualPoints);
1134 if (((mesh.points()[owner] - dualPoints[f[0]]) & n) > 0)
1136 WarningIn("calcDual") << "Incorrect orientation"
1137 << " on internal edge:" << edgeI
1138 << mesh.points()[mesh.edges()[edgeI][0]]
1139 << mesh.points()[mesh.edges()[edgeI][1]]
1149 dynDualFaces.shrink();
1150 dynDualOwner.shrink();
1151 dynDualNeighbour.shrink();
1152 dynDualRegion.shrink();
1154 OFstream str("dualInternalFaces.obj");
1155 Pout<< "polyDualMesh::calcDual : dumping internal faces to "
1156 << str.name() << endl;
1158 forAll(dualPoints, dualPointI)
1160 meshTools::writeOBJ(str, dualPoints[dualPointI]);
1162 forAll(dynDualFaces, dualFaceI)
1164 const face& f = dynDualFaces[dualFaceI];
1169 str<< ' ' << f[fp]+1;
1175 const label nInternalFaces = dynDualFaces.size();
1180 forAll(patches, patchI)
1182 const polyPatch& pp = patches[patchI];
1187 mesh.nCells() + pp.start() - nIntFaces,
1201 // Transfer face info to straight lists
1202 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1203 faceList dualFaces(dynDualFaces.shrink(), true);
1204 dynDualFaces.clear();
1206 labelList dualOwner(dynDualOwner.shrink(), true);
1207 dynDualOwner.clear();
1209 labelList dualNeighbour(dynDualNeighbour.shrink(), true);
1210 dynDualNeighbour.clear();
1212 labelList dualRegion(dynDualRegion.shrink(), true);
1213 dynDualRegion.clear();
1220 OFstream str("dualFaces.obj");
1221 Pout<< "polyDualMesh::calcDual : dumping all faces to "
1222 << str.name() << endl;
1224 forAll(dualPoints, dualPointI)
1226 meshTools::writeOBJ(str, dualPoints[dualPointI]);
1228 forAll(dualFaces, dualFaceI)
1230 const face& f = dualFaces[dualFaceI];
1235 str<< ' ' << f[fp]+1;
1242 cellList dualCells(mesh.nPoints());
1244 forAll(dualCells, cellI)
1246 dualCells[cellI].setSize(0);
1249 forAll(dualOwner, faceI)
1251 label cellI = dualOwner[faceI];
1253 labelList& cFaces = dualCells[cellI];
1255 label sz = cFaces.size();
1256 cFaces.setSize(sz+1);
1259 forAll(dualNeighbour, faceI)
1261 label cellI = dualNeighbour[faceI];
1265 labelList& cFaces = dualCells[cellI];
1267 label sz = cFaces.size();
1268 cFaces.setSize(sz+1);
1274 // Do upper-triangular face ordering. Determines face reordering map and
1275 // number of internal faces.
1290 inplaceReorder(oldToNew, dualFaces);
1291 inplaceReorder(oldToNew, dualOwner);
1292 inplaceReorder(oldToNew, dualNeighbour);
1293 inplaceReorder(oldToNew, dualRegion);
1294 forAll(dualCells, cellI)
1296 inplaceRenumber(oldToNew, dualCells[cellI]);
1301 labelList patchSizes(patches.size(), 0);
1303 forAll(dualRegion, faceI)
1305 if (dualRegion[faceI] >= 0)
1307 patchSizes[dualRegion[faceI]]++;
1311 labelList patchStarts(patches.size(), 0);
1313 label faceI = nInternalFaces;
1315 forAll(patches, patchI)
1317 patchStarts[patchI] = faceI;
1319 faceI += patchSizes[patchI];
1323 Pout<< "nFaces:" << dualFaces.size()
1324 << " patchSizes:" << patchSizes
1325 << " patchStarts:" << patchStarts
1329 // Add patches. First add zero sized (since mesh still 0 size)
1330 List<polyPatch*> dualPatches(patches.size());
1332 forAll(patches, patchI)
1334 const polyPatch& pp = patches[patchI];
1336 dualPatches[patchI] = pp.clone
1340 0, //patchSizes[patchI],
1341 0 //patchStarts[patchI]
1344 addPatches(dualPatches);
1349 xferMove(dualPoints),
1350 xferMove(dualFaces),
1351 xferMove(dualOwner),
1352 xferMove(dualNeighbour),
1359 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1361 // Construct from components
1362 Foam::polyDualMesh::polyDualMesh(const IOobject& io)
1370 time().findInstance(meshDir(), "cellPoint"),
1373 IOobject::MUST_READ,
1381 "boundaryFacePoint",
1382 time().findInstance(meshDir(), "boundaryFacePoint"),
1385 IOobject::MUST_READ,
1392 // Construct from polyMesh
1393 Foam::polyDualMesh::polyDualMesh
1395 const polyMesh& mesh,
1396 const labelList& featureEdges,
1397 const labelList& featurePoints
1403 xferCopy(pointField()), // to prevent any warnings "points not allocated"
1404 xferCopy(faceList()), // to prevent any warnings "faces not allocated"
1405 xferCopy(cellList())
1412 time().findInstance(meshDir(), "faces"),
1416 IOobject::AUTO_WRITE
1418 labelList(mesh.nCells(), -1)
1424 "boundaryFacePoint",
1425 time().findInstance(meshDir(), "faces"),
1429 IOobject::AUTO_WRITE
1431 labelList(mesh.nFaces() - mesh.nInternalFaces())
1434 calcDual(mesh, featureEdges, featurePoints);
1438 // Construct from polyMesh and feature angle
1439 Foam::polyDualMesh::polyDualMesh
1441 const polyMesh& mesh,
1442 const scalar featureCos
1448 xferCopy(pointField()), // to prevent any warnings "points not allocated"
1449 xferCopy(faceList()), // to prevent any warnings "faces not allocated"
1450 xferCopy(cellList())
1457 time().findInstance(meshDir(), "faces"),
1461 IOobject::AUTO_WRITE
1463 labelList(mesh.nCells(), -1)
1469 "boundaryFacePoint",
1470 time().findInstance(meshDir(), "faces"),
1474 IOobject::AUTO_WRITE
1476 labelList(mesh.nFaces() - mesh.nInternalFaces(), -1)
1479 labelList featureEdges, featurePoints;
1481 calcFeatures(mesh, featureCos, featureEdges, featurePoints);
1482 calcDual(mesh, featureEdges, featurePoints);
1486 void Foam::polyDualMesh::calcFeatures
1488 const polyMesh& mesh,
1489 const scalar featureCos,
1490 labelList& featureEdges,
1491 labelList& featurePoints
1494 // Create big primitivePatch for all outside.
1495 primitivePatch allBoundary
1500 mesh.nFaces() - mesh.nInternalFaces(),
1501 mesh.nInternalFaces()
1506 // For ease of use store patch number per face in allBoundary.
1507 labelList allRegion(allBoundary.size());
1509 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1511 forAll(patches, patchI)
1513 const polyPatch& pp = patches[patchI];
1517 allRegion[i + pp.start() - mesh.nInternalFaces()] = patchI;
1522 // Calculate patch/feature edges
1523 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1525 const labelListList& edgeFaces = allBoundary.edgeFaces();
1526 const vectorField& faceNormals = allBoundary.faceNormals();
1527 const labelList& meshPoints = allBoundary.meshPoints();
1529 boolList isFeatureEdge(edgeFaces.size(), false);
1531 forAll(edgeFaces, edgeI)
1533 const labelList& eFaces = edgeFaces[edgeI];
1535 if (eFaces.size() != 2)
1537 // Non-manifold. Problem?
1538 const edge& e = allBoundary.edges()[edgeI];
1540 WarningIn("polyDualMesh::calcFeatures") << "Edge "
1541 << meshPoints[e[0]] << ' ' << meshPoints[e[1]]
1542 << " coords:" << mesh.points()[meshPoints[e[0]]]
1543 << mesh.points()[meshPoints[e[1]]]
1544 << " has more than 2 faces connected to it:"
1545 << eFaces.size() << endl;
1547 isFeatureEdge[edgeI] = true;
1549 else if (allRegion[eFaces[0]] != allRegion[eFaces[1]])
1551 isFeatureEdge[edgeI] = true;
1555 (faceNormals[eFaces[0]] & faceNormals[eFaces[1]])
1559 isFeatureEdge[edgeI] = true;
1564 // Calculate feature points
1565 // ~~~~~~~~~~~~~~~~~~~~~~~~
1567 const labelListList& pointEdges = allBoundary.pointEdges();
1569 dynamicLabelList allFeaturePoints(pointEdges.size());
1571 forAll(pointEdges, pointI)
1573 const labelList& pEdges = pointEdges[pointI];
1575 label nFeatEdges = 0;
1579 if (isFeatureEdge[pEdges[i]])
1586 // Store in mesh vertex label
1587 allFeaturePoints.append(allBoundary.meshPoints()[pointI]);
1590 featurePoints.transfer(allFeaturePoints);
1594 OFstream str("featurePoints.obj");
1596 Pout<< "polyDualMesh::calcFeatures : dumping feature points to "
1597 << str.name() << endl;
1599 forAll(featurePoints, i)
1601 label pointI = featurePoints[i];
1602 meshTools::writeOBJ(str, mesh.points()[pointI]);
1607 // Get all feature edges.
1610 allBoundary.meshEdges
1618 mesh.nInternalFaces()
1623 dynamicLabelList allFeatureEdges(isFeatureEdge.size());
1624 forAll(isFeatureEdge, edgeI)
1626 if (isFeatureEdge[edgeI])
1628 // Store in mesh edge label.
1629 allFeatureEdges.append(meshEdges[edgeI]);
1632 featureEdges.transfer(allFeatureEdges);
1636 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1638 Foam::polyDualMesh::~polyDualMesh()
1642 // ************************************************************************* //