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 "meshDualiser.H"
31 #include "meshTools.H"
33 #include "polyTopoChange.H"
34 #include "mapPolyMesh.H"
35 #include "edgeFaceCirculator.H"
36 #include "mergePoints.H"
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(Foam::meshDualiser, 0);
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 void Foam::meshDualiser::checkPolyTopoChange(const polyTopoChange& meshMod)
48 // Assume no removed points
49 pointField points(meshMod.points().size());
50 forAll(meshMod.points(), i)
52 points[i] = meshMod.points()[i];
57 bool hasMerged = mergePoints
68 labelListList newToOld(invertOneToMany(newPoints.size(), oldToNew));
70 forAll(newToOld, newI)
72 if (newToOld[newI].size() != 1)
76 "meshDualiser::checkPolyTopoChange(const polyTopoChange&)"
77 ) << "duplicate verts:" << newToOld[newI]
79 << UIndirectList<point>(points, newToOld[newI])()
88 void Foam::meshDualiser::dumpPolyTopoChange
90 const polyTopoChange& meshMod,
91 const fileName& prefix
94 OFstream str1(prefix + "Faces.obj");
95 OFstream str2(prefix + "Edges.obj");
97 Info<< "Dumping current polyTopoChange. Faces to " << str1.name()
98 << " , points and edges to " << str2.name() << endl;
100 const DynamicList<point>& points = meshMod.points();
102 forAll(points, pointI)
104 meshTools::writeOBJ(str1, points[pointI]);
105 meshTools::writeOBJ(str2, points[pointI]);
108 const DynamicList<face>& faces = meshMod.faces();
112 const face& f = faces[faceI];
117 str1<< ' ' << f[fp]+1;
124 str2<< ' ' << f[fp]+1;
126 str2<< ' ' << f[0]+1 << nl;
131 //- Given cell and point on mesh finds the corresponding dualCell. Most
132 // points become only one cell but the feature points might be split.
133 Foam::label Foam::meshDualiser::findDualCell
139 const labelList& dualCells = pointToDualCells_[pointI];
141 if (dualCells.size() == 1)
147 label index = findIndex(mesh_.pointCells()[pointI], cellI);
149 return dualCells[index];
154 // Helper function to generate dualpoints on all boundary edges emanating
155 // from (boundary & feature) point
156 void Foam::meshDualiser::generateDualBoundaryEdges
158 const PackedBoolList& isBoundaryEdge,
160 polyTopoChange& meshMod
163 const labelList& pEdges = mesh_.pointEdges()[pointI];
165 forAll(pEdges, pEdgeI)
167 label edgeI = pEdges[pEdgeI];
169 if (edgeToDualPoint_[edgeI] == -1 && isBoundaryEdge.get(edgeI) == 1)
171 const edge& e = mesh_.edges()[edgeI];
173 edgeToDualPoint_[edgeI] = meshMod.addPoint
175 e.centre(mesh_.points()),
176 pointI, // masterPoint
185 // Return true if point on face has same dual cells on both owner and neighbour
187 bool Foam::meshDualiser::sameDualCell
193 if (!mesh_.isInternalFace(faceI))
195 FatalErrorIn("sameDualCell(const label, const label)")
196 << "face:" << faceI << " is not internal face."
197 << abort(FatalError);
200 label own = mesh_.faceOwner()[faceI];
201 label nei = mesh_.faceNeighbour()[faceI];
203 return findDualCell(own, pointI) == findDualCell(nei, pointI);
207 Foam::label Foam::meshDualiser::addInternalFace
209 const label masterPointI,
210 const label masterEdgeI,
211 const label masterFaceI,
213 const bool edgeOrder,
214 const label dualCell0,
215 const label dualCell1,
216 const DynamicList<label>& verts,
217 polyTopoChange& meshMod
222 if (edgeOrder != (dualCell0 < dualCell1))
229 pointField facePoints(meshMod.points(), newFace);
232 pointField newPoints;
233 bool hasMerged = mergePoints
244 FatalErrorIn("addInternalFace(..)")
245 << "verts:" << verts << " newFace:" << newFace
246 << " face points:" << facePoints
247 << abort(FatalError);
253 bool zoneFlip = false;
254 if (masterFaceI != -1)
256 zoneID = mesh_.faceZones().whichZone(masterFaceI);
260 const faceZone& fZone = mesh_.faceZones()[zoneID];
262 zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
268 if (dualCell0 < dualCell1)
270 dualFaceI = meshMod.addFace
275 masterPointI, // masterPointID
276 masterEdgeI, // masterEdgeID
277 masterFaceI, // masterFaceID
278 false, // flipFaceFlux
284 //pointField dualPoints(meshMod.points());
285 //vector n(newFace.normal(dualPoints));
287 //Pout<< "Generated internal dualFace:" << dualFaceI
288 // << " verts:" << newFace
289 // << " points:" << UIndirectList<point>(meshMod.points(), newFace)()
291 // << " between dualowner:" << dualCell0
292 // << " dualneigbour:" << dualCell1
297 dualFaceI = meshMod.addFace
302 masterPointI, // masterPointID
303 masterEdgeI, // masterEdgeID
304 masterFaceI, // masterFaceID
305 false, // flipFaceFlux
311 //pointField dualPoints(meshMod.points());
312 //vector n(newFace.normal(dualPoints));
314 //Pout<< "Generated internal dualFace:" << dualFaceI
315 // << " verts:" << newFace
316 // << " points:" << UIndirectList<point>(meshMod.points(), newFace)()
318 // << " between dualowner:" << dualCell1
319 // << " dualneigbour:" << dualCell0
326 Foam::label Foam::meshDualiser::addBoundaryFace
328 const label masterPointI,
329 const label masterEdgeI,
330 const label masterFaceI,
332 const label dualCellI,
334 const DynamicList<label>& verts,
335 polyTopoChange& meshMod
341 bool zoneFlip = false;
342 if (masterFaceI != -1)
344 zoneID = mesh_.faceZones().whichZone(masterFaceI);
348 const faceZone& fZone = mesh_.faceZones()[zoneID];
350 zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
354 label dualFaceI = meshMod.addFace
359 masterPointI, // masterPointID
360 masterEdgeI, // masterEdgeID
361 masterFaceI, // masterFaceID
362 false, // flipFaceFlux
368 //pointField dualPoints(meshMod.points());
369 //vector n(newFace.normal(dualPoints));
371 //Pout<< "Generated boundary dualFace:" << dualFaceI
372 // << " verts:" << newFace
373 // << " points:" << UIndirectList<point>(meshMod.points(), newFace)()
375 // << " on dualowner:" << dualCellI
381 // Walks around edgeI.
382 // splitFace=true : creates multiple faces
383 // splitFace=false: creates single face if same dual cells on both sides,
384 // multiple faces otherwise.
385 void Foam::meshDualiser::createFacesAroundEdge
387 const bool splitFace,
388 const PackedBoolList& isBoundaryEdge,
390 const label startFaceI,
391 polyTopoChange& meshMod,
395 const edge& e = mesh_.edges()[edgeI];
396 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
398 label fp = edgeFaceCirculator::getMinIndex
400 mesh_.faces()[startFaceI],
405 edgeFaceCirculator ie
411 isBoundaryEdge.get(edgeI) == 1 // isBoundaryEdge
415 bool edgeOrder = ie.sameOrder(e[0], e[1]);
416 label startFaceLabel = ie.faceLabel();
418 //Pout<< "At edge:" << edgeI << " verts:" << e
419 // << " points:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
420 // << " started walking at face:" << ie.faceLabel()
421 // << " verts:" << mesh_.faces()[ie.faceLabel()]
422 // << " edgeOrder:" << edgeOrder
423 // << " in direction of cell:" << ie.cellLabel()
426 // Walk and collect face.
427 DynamicList<label> verts(100);
429 if (edgeToDualPoint_[edgeI] != -1)
431 verts.append(edgeToDualPoint_[edgeI]);
433 if (faceToDualPoint_[ie.faceLabel()] != -1)
435 doneEFaces[findIndex(eFaces, ie.faceLabel())] = true;
436 verts.append(faceToDualPoint_[ie.faceLabel()]);
438 if (cellToDualPoint_[ie.cellLabel()] != -1)
440 verts.append(cellToDualPoint_[ie.cellLabel()]);
443 label currentDualCell0 = findDualCell(ie.cellLabel(), e[0]);
444 label currentDualCell1 = findDualCell(ie.cellLabel(), e[1]);
450 label faceI = ie.faceLabel();
452 // Mark face as visited.
453 doneEFaces[findIndex(eFaces, faceI)] = true;
455 if (faceToDualPoint_[faceI] != -1)
457 verts.append(faceToDualPoint_[faceI]);
460 label cellI = ie.cellLabel();
464 // At ending boundary face. We've stored the face point above
465 // so this is the whole face.
470 label dualCell0 = findDualCell(cellI, e[0]);
471 label dualCell1 = findDualCell(cellI, e[1]);
473 // Generate face. (always if splitFace=true; only if needed to
474 // separate cells otherwise)
479 dualCell0 != currentDualCell0
480 || dualCell1 != currentDualCell1
484 // Close current face.
488 edgeI, // masterEdgeI
498 currentDualCell0 = dualCell0;
499 currentDualCell1 = dualCell1;
502 if (edgeToDualPoint_[edgeI] != -1)
504 verts.append(edgeToDualPoint_[edgeI]);
506 if (faceToDualPoint_[faceI] != -1)
508 verts.append(faceToDualPoint_[faceI]);
512 if (cellToDualPoint_[cellI] != -1)
514 verts.append(cellToDualPoint_[cellI]);
521 // Back at start face (for internal edge only). See if this needs
523 if (isBoundaryEdge.get(edgeI) == 0)
525 label startDual = faceToDualPoint_[startFaceLabel];
527 if (startDual != -1 && findIndex(verts, startDual) == -1)
529 verts.append(startDual);
540 edgeI, // masterEdgeI
551 // Walks around circumference of faceI. Creates single face. Gets given
552 // starting (feature) edge to start from. Returns ending edge. (all edges
553 // in form of index in faceEdges)
554 void Foam::meshDualiser::createFaceFromInternalFace
558 polyTopoChange& meshMod
561 const face& f = mesh_.faces()[faceI];
562 const labelList& fEdges = mesh_.faceEdges()[faceI];
563 label own = mesh_.faceOwner()[faceI];
564 label nei = mesh_.faceNeighbour()[faceI];
566 //Pout<< "createFaceFromInternalFace : At face:" << faceI
568 // << " points:" << UIndirectList<point>(mesh_.points(), f)()
569 // << " started walking at edge:" << fEdges[fp]
570 // << " verts:" << mesh_.edges()[fEdges[fp]]
574 // Walk and collect face.
575 DynamicList<label> verts(100);
577 verts.append(faceToDualPoint_[faceI]);
578 verts.append(edgeToDualPoint_[fEdges[fp]]);
580 // Step to vertex after edge mid
583 // Get cells on either side of face at that point
584 label currentDualCell0 = findDualCell(own, f[fp]);
585 label currentDualCell1 = findDualCell(nei, f[fp]);
590 if (pointToDualPoint_[f[fp]] != -1)
592 verts.append(pointToDualPoint_[f[fp]]);
595 // Edge between fp and fp+1
596 label edgeI = fEdges[fp];
598 if (edgeToDualPoint_[edgeI] != -1)
600 verts.append(edgeToDualPoint_[edgeI]);
603 // Next vertex on edge
604 label nextFp = f.fcIndex(fp);
606 // Get dual cells on nextFp to check whether face needs closing.
607 label dualCell0 = findDualCell(own, f[nextFp]);
608 label dualCell1 = findDualCell(nei, f[nextFp]);
610 if (dualCell0 != currentDualCell0 || dualCell1 != currentDualCell1)
612 // Check: make sure that there is a midpoint on the edge.
613 if (edgeToDualPoint_[edgeI] == -1)
615 FatalErrorIn("createFacesFromInternalFace(..)")
616 << "face:" << faceI << " verts:" << f
617 << " points:" << UIndirectList<point>(mesh_.points(), f)()
618 << " no feature edge between " << f[fp]
619 << " and " << f[nextFp] << " although have different"
620 << " dual cells." << endl
621 << "point " << f[fp] << " has dual cells "
622 << currentDualCell0 << " and " << currentDualCell1
623 << " ; point "<< f[nextFp] << " has dual cells "
624 << dualCell0 << " and " << dualCell1
625 << abort(FatalError);
629 // Close current face.
635 faceI, // masterFaceI
650 // Given a point on a face converts the faces around the point.
651 // (pointFaces()). Gets starting face and marks off visited faces in donePFaces.
652 void Foam::meshDualiser::createFacesAroundBoundaryPoint
655 const label patchPointI,
656 const label startFaceI,
657 polyTopoChange& meshMod,
658 boolList& donePFaces // pFaces visited
661 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
662 const polyPatch& pp = patches[patchI];
663 const labelList& pFaces = pp.pointFaces()[patchPointI];
664 const labelList& own = mesh_.faceOwner();
666 label pointI = pp.meshPoints()[patchPointI];
668 if (pointToDualPoint_[pointI] == -1)
670 // Not a feature point. Loop over all connected
674 label faceI = startFaceI;
676 DynamicList<label> verts(4);
680 label index = findIndex(pFaces, faceI-pp.start());
682 // Has face been visited already?
683 if (donePFaces[index])
687 donePFaces[index] = true;
689 // Insert face centre
690 verts.append(faceToDualPoint_[faceI]);
692 label dualCellI = findDualCell(own[faceI], pointI);
694 // Get the edge before the patchPointI
695 const face& f = mesh_.faces()[faceI];
696 label fp = findIndex(f, pointI);
697 label prevFp = f.rcIndex(fp);
698 label edgeI = mesh_.faceEdges()[faceI][prevFp];
700 if (edgeToDualPoint_[edgeI] != -1)
702 verts.append(edgeToDualPoint_[edgeI]);
705 // Get next boundary face (whilst staying on edge).
706 edgeFaceCirculator circ
711 prevFp, // index of edge in face
712 true // isBoundaryEdge
719 while (mesh_.isInternalFace(circ.faceLabel()));
722 faceI = circ.faceLabel();
724 if (faceI < pp.start() || faceI >= pp.start()+pp.size())
728 "meshDualiser::createFacesAroundBoundaryPoint(..)"
729 ) << "Walked from face on patch:" << patchI
730 << " to face:" << faceI
731 << " fc:" << mesh_.faceCentres()[faceI]
732 << " on patch:" << patches.whichPatch(faceI)
733 << abort(FatalError);
736 // Check if different cell.
737 if (dualCellI != findDualCell(own[faceI], pointI))
741 "meshDualiser::createFacesAroundBoundaryPoint(..)"
742 ) << "Different dual cells but no feature edge"
743 << " inbetween point:" << pointI
744 << " coord:" << mesh_.points()[pointI]
745 << abort(FatalError);
751 label dualCellI = findDualCell(own[faceI], pointI);
753 //Bit dodgy: create dualface from the last face (instead of from
754 // the central point). This will also use the original faceZone to
755 // put the new face (which might span multiple original faces) in.
759 //pointI, // masterPointI
762 faceI, // masterFaceI
771 label faceI = startFaceI;
774 DynamicList<label> verts(mesh_.faces()[faceI].size());
777 verts.append(pointToDualPoint_[pointI]);
779 // Find edge between pointI and next point on face.
780 const labelList& fEdges = mesh_.faceEdges()[faceI];
781 label nextEdgeI = fEdges[findIndex(mesh_.faces()[faceI], pointI)];
782 if (edgeToDualPoint_[nextEdgeI] != -1)
784 verts.append(edgeToDualPoint_[nextEdgeI]);
789 label index = findIndex(pFaces, faceI-pp.start());
791 // Has face been visited already?
792 if (donePFaces[index])
796 donePFaces[index] = true;
799 verts.append(faceToDualPoint_[faceI]);
801 // Find edge before pointI on faceI
802 const labelList& fEdges = mesh_.faceEdges()[faceI];
803 const face& f = mesh_.faces()[faceI];
804 label prevFp = f.rcIndex(findIndex(f, pointI));
805 label edgeI = fEdges[prevFp];
807 if (edgeToDualPoint_[edgeI] != -1)
809 // Feature edge. Close any face so far. Note: uses face to
810 // create dualFace from. Could use pointI instead.
811 verts.append(edgeToDualPoint_[edgeI]);
816 faceI, // masterFaceI
817 findDualCell(own[faceI], pointI),
824 verts.append(pointToDualPoint_[pointI]);
825 verts.append(edgeToDualPoint_[edgeI]);
828 // Cross edgeI to next boundary face
829 edgeFaceCirculator circ
834 prevFp, // index of edge in face
835 true // isBoundaryEdge
842 while (mesh_.isInternalFace(circ.faceLabel()));
844 // Step to next face. Quit if not on same patch.
845 faceI = circ.faceLabel();
850 && faceI >= pp.start()
851 && faceI < pp.start()+pp.size()
854 if (verts.size() > 2)
856 // Note: face created from face, not from pointI
861 startFaceI, // masterFaceI
862 findDualCell(own[faceI], pointI),
872 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
874 Foam::meshDualiser::meshDualiser(const polyMesh& mesh)
877 pointToDualCells_(mesh_.nPoints()),
878 pointToDualPoint_(mesh_.nPoints(), -1),
879 cellToDualPoint_(mesh_.nCells()),
880 faceToDualPoint_(mesh_.nFaces(), -1),
881 edgeToDualPoint_(mesh_.nEdges(), -1)
885 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
888 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
890 void Foam::meshDualiser::setRefinement
892 const bool splitFace,
893 const labelList& featureFaces,
894 const labelList& featureEdges,
895 const labelList& singleCellFeaturePoints,
896 const labelList& multiCellFeaturePoints,
897 polyTopoChange& meshMod
900 const labelList& own = mesh_.faceOwner();
901 const labelList& nei = mesh_.faceNeighbour();
902 const vectorField& cellCentres = mesh_.cellCentres();
904 // Mark boundary edges and points.
905 // (Note: in 1.4.2 we can use the built-in mesh point ordering
907 PackedBoolList isBoundaryEdge(mesh_.nEdges());
908 for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
910 const labelList& fEdges = mesh_.faceEdges()[faceI];
914 isBoundaryEdge.set(fEdges[i], 1);
921 // This is a special mode where whenever we are walking around an edge
922 // every area through a cell becomes a separate dualface. So two
923 // dual cells will probably have more than one dualface between them!
924 // This mode implies that
925 // - all faces have to be feature faces since there has to be a
926 // dualpoint at the face centre.
927 // - all edges have to be feature edges ,,
928 boolList featureFaceSet(mesh_.nFaces(), false);
929 forAll(featureFaces, i)
931 featureFaceSet[featureFaces[i]] = true;
933 label faceI = findIndex(featureFaceSet, false);
939 "meshDualiser::setRefinement"
940 "(const labelList&, const labelList&, const labelList&"
941 ", const labelList, polyTopoChange&)"
942 ) << "In split-face-mode (splitFace=true) but not all faces"
943 << " marked as feature faces." << endl
944 << "First conflicting face:" << faceI
945 << " centre:" << mesh_.faceCentres()[faceI]
946 << abort(FatalError);
949 boolList featureEdgeSet(mesh_.nEdges(), false);
950 forAll(featureEdges, i)
952 featureEdgeSet[featureEdges[i]] = true;
954 label edgeI = findIndex(featureEdgeSet, false);
958 const edge& e = mesh_.edges()[edgeI];
961 "meshDualiser::setRefinement"
962 "(const labelList&, const labelList&, const labelList&"
963 ", const labelList, polyTopoChange&)"
964 ) << "In split-face-mode (splitFace=true) but not all edges"
965 << " marked as feature edges." << endl
966 << "First conflicting edge:" << edgeI
968 << " coords:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
969 << abort(FatalError);
974 // Check that all boundary faces are feature faces.
976 boolList featureFaceSet(mesh_.nFaces(), false);
977 forAll(featureFaces, i)
979 featureFaceSet[featureFaces[i]] = true;
983 label faceI = mesh_.nInternalFaces();
984 faceI < mesh_.nFaces();
988 if (!featureFaceSet[faceI])
992 "meshDualiser::setRefinement"
993 "(const labelList&, const labelList&, const labelList&"
994 ", const labelList, polyTopoChange&)"
995 ) << "Not all boundary faces marked as feature faces."
997 << "First conflicting face:" << faceI
998 << " centre:" << mesh_.faceCentres()[faceI]
999 << abort(FatalError);
1007 // Start creating cells, points, and faces (in that order)
1010 // 1. Mark which cells to create
1011 // Mostly every point becomes one cell but sometimes (for feature points)
1012 // all cells surrounding a feature point become cells. Also a non-manifold
1013 // point can create two cells! So a dual cell is uniquely defined by a
1014 // mesh point + cell (as in pointCells index)
1016 // 2. Mark which face centres to create
1018 // 3. Internal faces can now consist of
1019 // - only cell centres of walk around edge
1020 // - cell centres + face centres of walk around edge
1021 // - same but now other side is not a single cell
1023 // 4. Boundary faces (or internal faces between cell zones!) now consist of
1024 // - walk around boundary point.
1028 autoPtr<OFstream> dualCcStr;
1031 dualCcStr.reset(new OFstream("dualCc.obj"));
1032 Pout<< "Dumping centres of dual cells to " << dualCcStr().name()
1037 // Dual cells (from points)
1038 // ~~~~~~~~~~~~~~~~~~~~~~~~
1040 // pointToDualCells_[pointI]
1041 // - single entry : all cells surrounding point all become the same
1043 // - multiple entries: in order of pointCells.
1046 // feature points that become single cell
1047 forAll(singleCellFeaturePoints, i)
1049 label pointI = singleCellFeaturePoints[i];
1051 pointToDualPoint_[pointI] = meshMod.addPoint
1053 mesh_.points()[pointI],
1054 pointI, // masterPoint
1055 mesh_.pointZones().whichZone(pointI), // zoneID
1059 // Generate single cell
1060 pointToDualCells_[pointI].setSize(1);
1061 pointToDualCells_[pointI][0] = meshMod.addCell
1063 pointI, //masterPointID,
1069 if (dualCcStr.valid())
1071 meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointI]);
1075 // feature points that become multiple cells
1076 forAll(multiCellFeaturePoints, i)
1078 label pointI = multiCellFeaturePoints[i];
1080 if (pointToDualCells_[pointI].size() > 0)
1084 "meshDualiser::setRefinement"
1085 "(const labelList&, const labelList&, const labelList&"
1086 ", const labelList, polyTopoChange&)"
1087 ) << "Point " << pointI << " at:" << mesh_.points()[pointI]
1088 << " is both in singleCellFeaturePoints"
1089 << " and multiCellFeaturePoints."
1090 << abort(FatalError);
1093 pointToDualPoint_[pointI] = meshMod.addPoint
1095 mesh_.points()[pointI],
1096 pointI, // masterPoint
1097 mesh_.pointZones().whichZone(pointI), // zoneID
1101 // Create dualcell for every cell connected to dual point
1103 const labelList& pCells = mesh_.pointCells()[pointI];
1105 pointToDualCells_[pointI].setSize(pCells.size());
1107 forAll(pCells, pCellI)
1109 pointToDualCells_[pointI][pCellI] = meshMod.addCell
1111 pointI, //masterPointID
1115 mesh_.cellZones().whichZone(pCells[pCellI]) //zoneID
1117 if (dualCcStr.valid())
1122 0.5*(mesh_.points()[pointI]+cellCentres[pCells[pCellI]])
1128 forAll(mesh_.points(), pointI)
1130 if (pointToDualCells_[pointI].empty())
1132 pointToDualCells_[pointI].setSize(1);
1133 pointToDualCells_[pointI][0] = meshMod.addCell
1135 pointI, //masterPointID,
1142 if (dualCcStr.valid())
1144 meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointI]);
1150 // Dual points (from cell centres, feature faces, feature edges)
1151 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1153 forAll(cellToDualPoint_, cellI)
1155 cellToDualPoint_[cellI] = meshMod.addPoint
1158 mesh_.faces()[mesh_.cells()[cellI][0]][0], // masterPoint
1164 // From face to dual point
1166 forAll(featureFaces, i)
1168 label faceI = featureFaces[i];
1170 faceToDualPoint_[faceI] = meshMod.addPoint
1172 mesh_.faceCentres()[faceI],
1173 mesh_.faces()[faceI][0], // masterPoint
1178 // Detect whether different dual cells on either side of a face. This
1179 // would neccesitate having a dual face built from the face and thus a
1180 // dual point at the face centre.
1181 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1183 if (faceToDualPoint_[faceI] == -1)
1185 const face& f = mesh_.faces()[faceI];
1189 label ownDualCell = findDualCell(own[faceI], f[fp]);
1190 label neiDualCell = findDualCell(nei[faceI], f[fp]);
1192 if (ownDualCell != neiDualCell)
1194 faceToDualPoint_[faceI] = meshMod.addPoint
1196 mesh_.faceCentres()[faceI],
1197 f[fp], // masterPoint
1208 // From edge to dual point
1210 forAll(featureEdges, i)
1212 label edgeI = featureEdges[i];
1214 const edge& e = mesh_.edges()[edgeI];
1216 edgeToDualPoint_[edgeI] = meshMod.addPoint
1218 e.centre(mesh_.points()),
1219 e[0], // masterPoint
1225 // Detect whether different dual cells on either side of an edge. This
1226 // would neccesitate having a dual face built perpendicular to the edge
1227 // and thus a dual point at the mid of the edge.
1228 // Note: not really true - the face can be built without the edge centre!
1229 const labelListList& edgeCells = mesh_.edgeCells();
1231 forAll(edgeCells, edgeI)
1233 if (edgeToDualPoint_[edgeI] == -1)
1235 const edge& e = mesh_.edges()[edgeI];
1237 // We need a point on the edge if not all cells on both sides
1240 const labelList& eCells = mesh_.edgeCells()[edgeI];
1242 label dualE0 = findDualCell(eCells[0], e[0]);
1243 label dualE1 = findDualCell(eCells[0], e[1]);
1245 for (label i = 1; i < eCells.size(); i++)
1247 label newDualE0 = findDualCell(eCells[i], e[0]);
1249 if (dualE0 != newDualE0)
1251 edgeToDualPoint_[edgeI] = meshMod.addPoint
1253 e.centre(mesh_.points()),
1254 e[0], // masterPoint
1255 mesh_.pointZones().whichZone(e[0]), // zoneID
1262 label newDualE1 = findDualCell(eCells[i], e[1]);
1264 if (dualE1 != newDualE1)
1266 edgeToDualPoint_[edgeI] = meshMod.addPoint
1268 e.centre(mesh_.points()),
1269 e[1], // masterPoint
1270 mesh_.pointZones().whichZone(e[1]), // zoneID
1280 // Make sure all boundary edges emanating from feature points are
1281 // feature edges as well.
1282 forAll(singleCellFeaturePoints, i)
1284 generateDualBoundaryEdges
1287 singleCellFeaturePoints[i],
1291 forAll(multiCellFeaturePoints, i)
1293 generateDualBoundaryEdges
1296 multiCellFeaturePoints[i],
1302 // Check for duplicate points
1305 dumpPolyTopoChange(meshMod, "generatedPoints_");
1306 checkPolyTopoChange(meshMod);
1310 // Now we have all points and cells
1311 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1312 // - pointToDualCells_ : per point a single dualCell or multiple dualCells
1313 // - pointToDualPoint_ : per point -1 or the dual point at the coordinate
1314 // - edgeToDualPoint_ : per edge -1 or the edge centre
1315 // - faceToDualPoint_ : per face -1 or the face centre
1316 // - cellToDualPoint_ : per cell the cell centre
1317 // Now we have to walk all edges and construct faces. Either single face
1318 // per edge or multiple (-if nonmanifold edge -if different dualcells)
1320 const edgeList& edges = mesh_.edges();
1322 forAll(edges, edgeI)
1324 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
1326 boolList doneEFaces(eFaces.size(), false);
1332 // We found a face that hasn't yet been visited. This might
1333 // happen for non-manifold edges where a single edge can
1334 // become multiple faces.
1336 label startFaceI = eFaces[i];
1338 //Pout<< "Walking edge:" << edgeI
1339 // << " points:" << mesh_.points()[e[0]]
1340 // << mesh_.points()[e[1]]
1341 // << " startFace:" << startFaceI
1342 // << " at:" << mesh_.faceCentres()[startFaceI]
1345 createFacesAroundEdge
1360 dumpPolyTopoChange(meshMod, "generatedFacesFromEdges_");
1363 // Create faces from feature faces. These can be internal or external faces.
1364 // - feature face : centre needs to be included.
1365 // - single cells on either side: triangulate
1366 // - multiple cells: create single face between unique cell pair. Only
1367 // create face where cells differ on either side.
1368 // - non-feature face : inbetween cell zones.
1369 forAll(faceToDualPoint_, faceI)
1371 if (faceToDualPoint_[faceI] != -1 && mesh_.isInternalFace(faceI))
1373 const face& f = mesh_.faces()[faceI];
1374 const labelList& fEdges = mesh_.faceEdges()[faceI];
1381 // Find edge that is in dual mesh and where the
1382 // next point (fp+1) has different dual cells on either side.
1383 bool foundStart = false;
1389 edgeToDualPoint_[fEdges[fp]] != -1
1390 && !sameDualCell(faceI, f.nextLabel(fp))
1405 // Walk from edge fp and generate a face.
1406 createFaceFromInternalFace
1419 dumpPolyTopoChange(meshMod, "generatedFacesFromFeatFaces_");
1423 // Create boundary faces. Every boundary point has one or more dualcells.
1424 // These need to be closed.
1425 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1427 forAll(patches, patchI)
1429 const polyPatch& pp = patches[patchI];
1431 const labelListList& pointFaces = pp.pointFaces();
1433 forAll(pointFaces, patchPointI)
1435 const labelList& pFaces = pointFaces[patchPointI];
1437 boolList donePFaces(pFaces.size(), false);
1444 label startFaceI = pp.start()+pFaces[i];
1446 //Pout<< "Walking around point:" << pointI
1447 // << " coord:" << mesh_.points()[pointI]
1448 // << " on patch:" << patchI
1449 // << " startFace:" << startFaceI
1450 // << " at:" << mesh_.faceCentres()[startFaceI]
1453 createFacesAroundBoundaryPoint
1459 donePFaces // pFaces visited
1468 dumpPolyTopoChange(meshMod, "generatedFacesFromBndFaces_");
1474 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1477 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
1480 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
1483 // ************************************************************************* //