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
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.setSize(pFaces.size()+2+1);
240 // Store dualVertex for feature edge
241 dualFace.append(pointToDualPoint[meshPointI]);
245 dualFace.setSize(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.shrink());
418 featEdgeIndices2.transfer(featEdgeIndices.shrink());
419 featEdgeIndices.clear();
425 // Correct featEdgeIndices for change in dualFace2
426 forAll(featEdgeIndices2, i)
428 featEdgeIndices2[i] = dualFace2.size() -1 - featEdgeIndices2[i];
430 // Reverse indices (might not be nessecary but do anyway)
431 reverse(featEdgeIndices2);
436 void Foam::polyDualMesh::splitFace
438 const polyPatch& patch,
439 const labelList& pointToDualPoint,
442 const labelList& dualFace,
443 const labelList& featEdgeIndices,
445 DynamicList<face>& dualFaces,
446 DynamicList<label>& dualOwner,
447 DynamicList<label>& dualNeighbour,
448 DynamicList<label>& dualRegion
452 // Split face because of feature edges/points
453 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
454 label meshPointI = patch.meshPoints()[pointI];
456 if (pointToDualPoint[meshPointI] >= 0)
458 // Feature point. Do face-centre decomposition.
460 if (featEdgeIndices.size() < 2)
462 // Feature point but no feature edges. Not handled at the moment
463 dualFaces.append(face(dualFace));
464 dualOwner.append(meshPointI);
465 dualNeighbour.append(-1);
466 dualRegion.append(patch.index());
470 // Do 'face-centre' decomposition. Start from first feature
471 // edge create face up until next feature edge.
473 forAll(featEdgeIndices, i)
475 label startFp = featEdgeIndices[i];
477 label endFp = featEdgeIndices[(i+1) % featEdgeIndices.size()];
479 // Collect face from startFp to endFp
484 sz = endFp - startFp + 2;
488 sz = endFp + dualFace.size() - startFp + 2;
492 // feature point becomes face centre.
493 subFace[0] = pointToDualPoint[patch.meshPoints()[pointI]];
495 // Copy from startFp up to endFp.
496 for (label subFp = 1; subFp < subFace.size(); subFp++)
498 subFace[subFp] = dualFace[startFp];
500 startFp = (startFp+1) % dualFace.size();
503 dualFaces.append(face(subFace));
504 dualOwner.append(meshPointI);
505 dualNeighbour.append(-1);
506 dualRegion.append(patch.index());
512 // No feature point. Check if feature edges.
513 if (featEdgeIndices.size() < 2)
515 // Not enough feature edges. No split.
516 dualFaces.append(face(dualFace));
517 dualOwner.append(meshPointI);
518 dualNeighbour.append(-1);
519 dualRegion.append(patch.index());
523 // Multiple feature edges but no feature point.
524 // Split face along feature edges. Gives weird result if
525 // number of feature edges > 2.
527 // Storage for new face
528 DynamicList<label> subFace(dualFace.size());
530 forAll(featEdgeIndices, featI)
532 label startFp = featEdgeIndices[featI];
533 label endFp = featEdgeIndices[featEdgeIndices.fcIndex(featI)];
539 label vertI = dualFace[fp];
541 subFace.append(vertI);
548 fp = dualFace.fcIndex(fp);
551 if (subFace.size() > 2)
553 // Enough vertices to create a face from.
556 dualFaces.append(face(subFace));
557 dualOwner.append(meshPointI);
558 dualNeighbour.append(-1);
559 dualRegion.append(patch.index());
565 if (subFace.size() > 2)
567 // Enough vertices to create a face from.
570 dualFaces.append(face(subFace));
571 dualOwner.append(meshPointI);
572 dualNeighbour.append(-1);
573 dualRegion.append(patch.index());
582 // Create boundary face for every point in patch
583 void Foam::polyDualMesh::dualPatch
585 const polyPatch& patch,
586 const label patchToDualOffset,
587 const labelList& edgeToDualPoint,
588 const labelList& pointToDualPoint,
590 const pointField& dualPoints,
592 DynamicList<face>& dualFaces,
593 DynamicList<label>& dualOwner,
594 DynamicList<label>& dualNeighbour,
595 DynamicList<label>& dualRegion
598 const labelList& meshEdges = patch.meshEdges();
600 // Whether edge has been done.
602 // 1 : done e.start()
605 labelList doneEdgeSide(meshEdges.size(), 0);
607 boolList donePoint(patch.nPoints(), false);
610 // Do points on edge of patch
611 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
613 forAll(doneEdgeSide, patchEdgeI)
615 const labelList& eFaces = patch.edgeFaces()[patchEdgeI];
617 if (eFaces.size() == 1)
619 const edge& e = patch.edges()[patchEdgeI];
623 label bitMask = 1<<eI;
625 if ((doneEdgeSide[patchEdgeI] & bitMask) == 0)
627 // Construct face by walking around e[eI] starting from
630 label pointI = e[eI];
632 label edgeI = patchEdgeI;
647 // Now edgeI is end edge. Mark as visited
648 if (patch.edges()[edgeI][0] == pointI)
650 doneEdgeSide[edgeI] |= 1;
654 doneEdgeSide[edgeI] |= 2;
657 dualFaces.append(face(dualFace));
658 dualOwner.append(patch.meshPoints()[pointI]);
659 dualNeighbour.append(-1);
660 dualRegion.append(patch.index());
662 doneEdgeSide[patchEdgeI] |= bitMask;
663 donePoint[pointI] = true;
671 // Do patch-internal points
672 // ~~~~~~~~~~~~~~~~~~~~~~~~
674 forAll(donePoint, pointI)
676 if (!donePoint[pointI])
678 labelList dualFace, featEdgeIndices;
680 collectPatchInternalFace
686 patch.pointEdges()[pointI][0], // Arbitrary starting edge
692 //- Either keep in one piece or split face according to feature.
694 //// Keep face in one piece.
695 //dualFaces.append(face(dualFace));
696 //dualOwner.append(patch.meshPoints()[pointI]);
697 //dualNeighbour.append(-1);
698 //dualRegion.append(patch.index());
714 donePoint[pointI] = true;
720 void Foam::polyDualMesh::calcDual
722 const polyMesh& mesh,
723 const labelList& featureEdges,
724 const labelList& featurePoints
727 const polyBoundaryMesh& patches = mesh.boundaryMesh();
728 const label nIntFaces = mesh.nInternalFaces();
731 // Get patch for all of outside
732 primitivePatch allBoundary
737 mesh.nFaces() - nIntFaces,
743 // Correspondence from patch edge to mesh edge.
746 allBoundary.meshEdges
750 SubList<label>(mesh.faceOwner(), allBoundary.size(), nIntFaces)
755 pointSet nonManifoldPoints
759 meshEdges.size() / 100
762 allBoundary.checkPointManifold(true, &nonManifoldPoints);
764 if (nonManifoldPoints.size() > 0)
766 nonManifoldPoints.write();
770 "polyDualMesh::calcDual(const polyMesh&, const labelList&"
771 ", const labelList&)"
772 ) << "There are " << nonManifoldPoints.size() << " points where"
773 << " the outside of the mesh is non-manifold." << nl
774 << "Such a mesh cannot be converted to a dual." << nl
775 << "Writing points at non-manifold sites to pointSet "
776 << nonManifoldPoints.name()
785 // mesh label dualMesh vertex
786 // ---------- ---------------
788 // faceI nCells+faceI-nIntFaces
789 // featEdgeI nCells+nFaces-nIntFaces+featEdgeI
790 // featPointI nCells+nFaces-nIntFaces+nFeatEdges+featPointI
792 pointField dualPoints
794 mesh.nCells() // cell centres
795 + mesh.nFaces() - nIntFaces // boundary face centres
796 + featureEdges.size() // additional boundary edges
797 + featurePoints.size() // additional boundary points
800 label dualPointI = 0;
804 const pointField& cellCentres = mesh.cellCentres();
806 cellPoint_.setSize(cellCentres.size());
808 forAll(cellCentres, cellI)
810 cellPoint_[cellI] = dualPointI;
811 dualPoints[dualPointI++] = cellCentres[cellI];
814 // Boundary faces centres
815 const pointField& faceCentres = mesh.faceCentres();
817 boundaryFacePoint_.setSize(mesh.nFaces() - nIntFaces);
819 for (label faceI = nIntFaces; faceI < mesh.nFaces(); faceI++)
821 boundaryFacePoint_[faceI - nIntFaces] = dualPointI;
822 dualPoints[dualPointI++] = faceCentres[faceI];
826 // >0 : dual point label (edge is feature edge)
827 // -1 : is boundary edge.
828 // -2 : is internal edge.
829 labelList edgeToDualPoint(mesh.nEdges(), -2);
831 forAll(meshEdges, patchEdgeI)
833 label edgeI = meshEdges[patchEdgeI];
835 edgeToDualPoint[edgeI] = -1;
838 forAll(featureEdges, i)
840 label edgeI = featureEdges[i];
842 const edge& e = mesh.edges()[edgeI];
844 edgeToDualPoint[edgeI] = dualPointI;
845 dualPoints[dualPointI++] = e.centre(mesh.points());
851 // >0 : dual point label (point is feature point)
852 // -1 : is point on edge of patch
853 // -2 : is point on patch (but not on edge)
854 // -3 : is internal point.
855 labelList pointToDualPoint(mesh.nPoints(), -3);
857 forAll(patches, patchI)
859 const labelList& meshPoints = patches[patchI].meshPoints();
861 forAll(meshPoints, i)
863 pointToDualPoint[meshPoints[i]] = -2;
866 const labelListList& loops = patches[patchI].edgeLoops();
870 const labelList& loop = loops[i];
874 pointToDualPoint[meshPoints[loop[j]]] = -1;
879 forAll(featurePoints, i)
881 label pointI = featurePoints[i];
883 pointToDualPoint[pointI] = dualPointI;
884 dualPoints[dualPointI++] = mesh.points()[pointI];
888 // Storage for new faces.
889 // Dynamic sized since we don't know size.
891 DynamicList<face> dynDualFaces(mesh.nEdges());
892 DynamicList<label> dynDualOwner(mesh.nEdges());
893 DynamicList<label> dynDualNeighbour(mesh.nEdges());
894 DynamicList<label> dynDualRegion(mesh.nEdges());
897 // Generate faces from edges on the boundary
898 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
900 forAll(meshEdges, patchEdgeI)
902 label edgeI = meshEdges[patchEdgeI];
904 const edge& e = mesh.edges()[edgeI];
907 label neighbour = -1;
920 // Find the boundary faces using the edge.
921 const labelList& patchFaces = allBoundary.edgeFaces()[patchEdgeI];
923 if (patchFaces.size() != 2)
925 FatalErrorIn("polyDualMesh::calcDual")
926 << "Cannot handle edges with " << patchFaces.size()
927 << " connected boundary faces."
928 << abort(FatalError);
931 label face0 = patchFaces[0] + nIntFaces;
932 const face& f0 = mesh.faces()[face0];
934 label face1 = patchFaces[1] + nIntFaces;
936 // We want to start walking from patchFaces[0] or patchFaces[1],
937 // depending on which one uses owner,neighbour in the right order.
939 label startFaceI = -1;
942 label index = findIndex(f0, neighbour);
944 if (f0.nextLabel(index) == owner)
955 // Now walk from startFaceI to cell to face to cell etc. until endFaceI
957 DynamicList<label> dualFace;
959 if (edgeToDualPoint[edgeI] >= 0)
961 // Number of cells + 2 boundary faces + feature edge point
962 dualFace.setSize(mesh.edgeCells()[edgeI].size()+2+1);
963 // Store dualVertex for feature edge
964 dualFace.append(edgeToDualPoint[edgeI]);
968 dualFace.setSize(mesh.edgeCells()[edgeI].size()+2);
971 // Store dual vertex for starting face.
972 dualFace.append(mesh.nCells() + startFaceI - nIntFaces);
974 label cellI = mesh.faceOwner()[startFaceI];
975 label faceI = startFaceI;
979 // Store dual vertex from cellI.
980 dualFace.append(cellI);
982 // Cross cell to other face on edge.
984 meshTools::getEdgeFaces(mesh, cellI, edgeI, f0, f1);
995 // Cross face to other cell.
996 if (faceI == endFaceI)
1001 if (mesh.faceOwner()[faceI] == cellI)
1003 cellI = mesh.faceNeighbour()[faceI];
1007 cellI = mesh.faceOwner()[faceI];
1011 // Store dual vertex for endFace.
1012 dualFace.append(mesh.nCells() + endFaceI - nIntFaces);
1014 dynDualFaces.append(face(dualFace.shrink()));
1015 dynDualOwner.append(owner);
1016 dynDualNeighbour.append(neighbour);
1017 dynDualRegion.append(-1);
1020 // Check orientation.
1021 const face& f = dynDualFaces[dynDualFaces.size()-1];
1022 vector n = f.normal(dualPoints);
1023 if (((mesh.points()[owner] - dualPoints[f[0]]) & n) > 0)
1025 WarningIn("calcDual") << "Incorrect orientation"
1026 << " on boundary edge:" << edgeI
1027 << mesh.points()[mesh.edges()[edgeI][0]]
1028 << mesh.points()[mesh.edges()[edgeI][1]]
1035 // Generate faces from internal edges
1036 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1038 forAll(edgeToDualPoint, edgeI)
1040 if (edgeToDualPoint[edgeI] == -2)
1044 // Find dual owner, neighbour
1046 const edge& e = mesh.edges()[edgeI];
1049 label neighbour = -1;
1062 // Get a starting cell
1063 const labelList& eCells = mesh.edgeCells()[edgeI];
1065 label cellI = eCells[0];
1067 // Get the two faces on the cell and edge.
1069 meshTools::getEdgeFaces(mesh, cellI, edgeI, face0, face1);
1071 // Find the starting face by looking at the order in which
1072 // the face uses the owner, neighbour
1073 const face& f0 = mesh.faces()[face0];
1075 label index = findIndex(f0, neighbour);
1077 bool f0OrderOk = (f0.nextLabel(index) == owner);
1079 label startFaceI = -1;
1081 if (f0OrderOk == (mesh.faceOwner()[face0] == cellI))
1090 // Walk face-cell-face until starting face reached.
1091 DynamicList<label> dualFace(mesh.edgeCells()[edgeI].size());
1093 label faceI = startFaceI;
1097 // Store dual vertex from cellI.
1098 dualFace.append(cellI);
1100 // Cross cell to other face on edge.
1102 meshTools::getEdgeFaces(mesh, cellI, edgeI, f0, f1);
1113 // Cross face to other cell.
1114 if (faceI == startFaceI)
1119 if (mesh.faceOwner()[faceI] == cellI)
1121 cellI = mesh.faceNeighbour()[faceI];
1125 cellI = mesh.faceOwner()[faceI];
1129 dynDualFaces.append(face(dualFace.shrink()));
1130 dynDualOwner.append(owner);
1131 dynDualNeighbour.append(neighbour);
1132 dynDualRegion.append(-1);
1135 // Check orientation.
1136 const face& f = dynDualFaces[dynDualFaces.size()-1];
1137 vector n = f.normal(dualPoints);
1138 if (((mesh.points()[owner] - dualPoints[f[0]]) & n) > 0)
1140 WarningIn("calcDual") << "Incorrect orientation"
1141 << " on internal edge:" << edgeI
1142 << mesh.points()[mesh.edges()[edgeI][0]]
1143 << mesh.points()[mesh.edges()[edgeI][1]]
1153 dynDualFaces.shrink();
1154 dynDualOwner.shrink();
1155 dynDualNeighbour.shrink();
1156 dynDualRegion.shrink();
1158 OFstream str("dualInternalFaces.obj");
1159 Pout<< "polyDualMesh::calcDual : dumping internal faces to "
1160 << str.name() << endl;
1162 forAll(dualPoints, dualPointI)
1164 meshTools::writeOBJ(str, dualPoints[dualPointI]);
1166 forAll(dynDualFaces, dualFaceI)
1168 const face& f = dynDualFaces[dualFaceI];
1173 str<< ' ' << f[fp]+1;
1179 const label nInternalFaces = dynDualFaces.size();
1184 forAll(patches, patchI)
1186 const polyPatch& pp = patches[patchI];
1191 mesh.nCells() + pp.start() - nIntFaces,
1205 // Transfer face info to straight lists
1206 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1207 faceList dualFaces(dynDualFaces.shrink(), true);
1208 dynDualFaces.clear();
1210 labelList dualOwner(dynDualOwner.shrink(), true);
1211 dynDualOwner.clear();
1213 labelList dualNeighbour(dynDualNeighbour.shrink(), true);
1214 dynDualNeighbour.clear();
1216 labelList dualRegion(dynDualRegion.shrink(), true);
1217 dynDualRegion.clear();
1224 OFstream str("dualFaces.obj");
1225 Pout<< "polyDualMesh::calcDual : dumping all faces to "
1226 << str.name() << endl;
1228 forAll(dualPoints, dualPointI)
1230 meshTools::writeOBJ(str, dualPoints[dualPointI]);
1232 forAll(dualFaces, dualFaceI)
1234 const face& f = dualFaces[dualFaceI];
1239 str<< ' ' << f[fp]+1;
1246 cellList dualCells(mesh.nPoints());
1248 forAll(dualCells, cellI)
1250 dualCells[cellI].setSize(0);
1253 forAll(dualOwner, faceI)
1255 label cellI = dualOwner[faceI];
1257 labelList& cFaces = dualCells[cellI];
1259 label sz = cFaces.size();
1260 cFaces.setSize(sz+1);
1263 forAll(dualNeighbour, faceI)
1265 label cellI = dualNeighbour[faceI];
1269 labelList& cFaces = dualCells[cellI];
1271 label sz = cFaces.size();
1272 cFaces.setSize(sz+1);
1278 // Do upper-triangular face ordering. Determines face reordering map and
1279 // number of internal faces.
1294 inplaceReorder(oldToNew, dualFaces);
1295 inplaceReorder(oldToNew, dualOwner);
1296 inplaceReorder(oldToNew, dualNeighbour);
1297 inplaceReorder(oldToNew, dualRegion);
1298 forAll(dualCells, cellI)
1300 inplaceRenumber(oldToNew, dualCells[cellI]);
1305 labelList patchSizes(patches.size(), 0);
1307 forAll(dualRegion, faceI)
1309 if (dualRegion[faceI] >= 0)
1311 patchSizes[dualRegion[faceI]]++;
1315 labelList patchStarts(patches.size(), 0);
1317 label faceI = nInternalFaces;
1319 forAll(patches, patchI)
1321 patchStarts[patchI] = faceI;
1323 faceI += patchSizes[patchI];
1327 Pout<< "nFaces:" << dualFaces.size()
1328 << " patchSizes:" << patchSizes
1329 << " patchStarts:" << patchStarts
1333 // Add patches. First add zero sized (since mesh still 0 size)
1334 List<polyPatch*> dualPatches(patches.size());
1336 forAll(patches, patchI)
1338 const polyPatch& pp = patches[patchI];
1340 dualPatches[patchI] = pp.clone
1344 0, //patchSizes[patchI],
1345 0 //patchStarts[patchI]
1348 addPatches(dualPatches);
1364 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1366 // Construct from components
1367 Foam::polyDualMesh::polyDualMesh(const IOobject& io)
1375 time().findInstance(meshDir(), "cellPoint"),
1378 IOobject::MUST_READ,
1386 "boundaryFacePoint",
1387 time().findInstance(meshDir(), "boundaryFacePoint"),
1390 IOobject::MUST_READ,
1397 // Construct from polyMesh
1398 Foam::polyDualMesh::polyDualMesh
1400 const polyMesh& mesh,
1401 const labelList& featureEdges,
1402 const labelList& featurePoints
1417 time().findInstance(meshDir(), "faces"),
1421 IOobject::AUTO_WRITE
1423 labelList(mesh.nCells(), -1)
1429 "boundaryFacePoint",
1430 time().findInstance(meshDir(), "faces"),
1434 IOobject::AUTO_WRITE
1436 labelList(mesh.nFaces() - mesh.nInternalFaces())
1439 calcDual(mesh, featureEdges, featurePoints);
1443 // Construct from polyMesh and feature angle
1444 Foam::polyDualMesh::polyDualMesh
1446 const polyMesh& mesh,
1447 const scalar featureCos
1453 pointField(0), // to prevent any warnings "points not allocated"
1454 faceList(0), // ,, faces ,,
1462 time().findInstance(meshDir(), "faces"),
1466 IOobject::AUTO_WRITE
1468 labelList(mesh.nCells(), -1)
1474 "boundaryFacePoint",
1475 time().findInstance(meshDir(), "faces"),
1479 IOobject::AUTO_WRITE
1481 labelList(mesh.nFaces() - mesh.nInternalFaces(), -1)
1484 labelList featureEdges, featurePoints;
1486 calcFeatures(mesh, featureCos, featureEdges, featurePoints);
1488 calcDual(mesh, featureEdges, featurePoints);
1492 void Foam::polyDualMesh::calcFeatures
1494 const polyMesh& mesh,
1495 const scalar featureCos,
1496 labelList& featureEdges,
1497 labelList& featurePoints
1500 // Create big primitivePatch for all outside.
1501 primitivePatch allBoundary
1506 mesh.nFaces() - mesh.nInternalFaces(),
1507 mesh.nInternalFaces()
1512 // For ease of use store patch number per face in allBoundary.
1513 labelList allRegion(allBoundary.size());
1515 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1517 forAll(patches, patchI)
1519 const polyPatch& pp = patches[patchI];
1523 allRegion[i + pp.start() - mesh.nInternalFaces()] = patchI;
1528 // Calculate patch/feature edges
1529 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1531 const labelListList& edgeFaces = allBoundary.edgeFaces();
1532 const vectorField& faceNormals = allBoundary.faceNormals();
1533 const labelList& meshPoints = allBoundary.meshPoints();
1535 boolList isFeatureEdge(edgeFaces.size(), false);
1537 forAll(edgeFaces, edgeI)
1539 const labelList& eFaces = edgeFaces[edgeI];
1541 if (eFaces.size() != 2)
1543 // Non-manifold. Problem?
1544 const edge& e = allBoundary.edges()[edgeI];
1546 WarningIn("polyDualMesh::calcFeatures") << "Edge "
1547 << meshPoints[e[0]] << ' ' << meshPoints[e[1]]
1548 << " coords:" << mesh.points()[meshPoints[e[0]]]
1549 << mesh.points()[meshPoints[e[1]]]
1550 << " has more than 2 faces connected to it:"
1551 << eFaces.size() << endl;
1553 isFeatureEdge[edgeI] = true;
1555 else if (allRegion[eFaces[0]] != allRegion[eFaces[1]])
1557 isFeatureEdge[edgeI] = true;
1561 (faceNormals[eFaces[0]] & faceNormals[eFaces[1]])
1565 isFeatureEdge[edgeI] = true;
1570 // Calculate feature points
1571 // ~~~~~~~~~~~~~~~~~~~~~~~~
1573 const labelListList& pointEdges = allBoundary.pointEdges();
1575 DynamicList<label> allFeaturePoints(pointEdges.size());
1577 forAll(pointEdges, pointI)
1579 const labelList& pEdges = pointEdges[pointI];
1581 label nFeatEdges = 0;
1585 if (isFeatureEdge[pEdges[i]])
1592 // Store in mesh vertex label
1593 allFeaturePoints.append(allBoundary.meshPoints()[pointI]);
1596 featurePoints.transfer(allFeaturePoints.shrink());
1597 allFeaturePoints.clear();
1601 OFstream str("featurePoints.obj");
1603 Pout<< "polyDualMesh::calcFeatures : dumping feature points to "
1604 << str.name() << endl;
1606 forAll(featurePoints, i)
1608 label pointI = featurePoints[i];
1609 meshTools::writeOBJ(str, mesh.points()[pointI]);
1614 // Get all feature edges.
1617 allBoundary.meshEdges
1625 mesh.nInternalFaces()
1630 DynamicList<label> allFeatureEdges(isFeatureEdge.size());
1631 forAll(isFeatureEdge, edgeI)
1633 if (isFeatureEdge[edgeI])
1635 // Store in mesh edge label.
1636 allFeatureEdges.append(meshEdges[edgeI]);
1639 featureEdges.transfer(allFeatureEdges.shrink());
1640 allFeatureEdges.clear();
1644 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1646 Foam::polyDualMesh::~polyDualMesh()
1650 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1653 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1656 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
1659 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
1662 // ************************************************************************* //