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 "meshDualiser.H"
30 #include "meshTools.H"
32 #include "directTopoChange.H"
33 #include "mapPolyMesh.H"
34 #include "edgeFaceCirculator.H"
35 #include "mergePoints.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 defineTypeNameAndDebug(Foam::meshDualiser, 0);
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 void Foam::meshDualiser::checkPolyTopoChange(const directTopoChange& meshMod)
47 // Assume no removed points
48 pointField points(meshMod.points().size());
49 forAll(meshMod.points(), i)
51 points[i] = meshMod.points()[i];
56 bool hasMerged = mergePoints
67 labelListList newToOld(invertOneToMany(newPoints.size(), oldToNew));
69 forAll(newToOld, newI)
71 if (newToOld[newI].size() != 1)
75 "meshDualiser::checkPolyTopoChange(const directTopoChange&)"
76 ) << "duplicate verts:" << newToOld[newI]
78 << UIndirectList<point>(points, newToOld[newI])()
87 void Foam::meshDualiser::dumpPolyTopoChange
89 const directTopoChange& meshMod,
90 const fileName& prefix
93 OFstream str1(prefix + "Faces.obj");
94 OFstream str2(prefix + "Edges.obj");
96 Info<< "Dumping current directTopoChange. Faces to " << str1.name()
97 << " , points and edges to " << str2.name() << endl;
99 const DynamicList<point>& points = meshMod.points();
101 forAll(points, pointI)
103 meshTools::writeOBJ(str1, points[pointI]);
104 meshTools::writeOBJ(str2, points[pointI]);
107 const DynamicList<face>& faces = meshMod.faces();
111 const face& f = faces[faceI];
116 str1<< ' ' << f[fp]+1;
123 str2<< ' ' << f[fp]+1;
125 str2<< ' ' << f[0]+1 << nl;
130 //- Given cell and point on mesh finds the corresponding dualCell. Most
131 // points become only one cell but the feature points might be split.
132 Foam::label Foam::meshDualiser::findDualCell
138 const labelList& dualCells = pointToDualCells_[pointI];
140 if (dualCells.size() == 1)
146 label index = findIndex(mesh_.pointCells()[pointI], cellI);
148 return dualCells[index];
153 // Helper function to generate dualpoints on all boundary edges emanating
154 // from (boundary & feature) point
155 void Foam::meshDualiser::generateDualBoundaryEdges
157 const PackedBoolList& isBoundaryEdge,
159 directTopoChange& meshMod
162 const labelList& pEdges = mesh_.pointEdges()[pointI];
164 forAll(pEdges, pEdgeI)
166 label edgeI = pEdges[pEdgeI];
168 if (edgeToDualPoint_[edgeI] == -1 && isBoundaryEdge.get(edgeI) == 1)
170 const edge& e = mesh_.edges()[edgeI];
172 edgeToDualPoint_[edgeI] = meshMod.addPoint
174 e.centre(mesh_.points()),
175 pointI, // masterPoint
184 // Return true if point on face has same dual cells on both owner and neighbour
186 bool Foam::meshDualiser::sameDualCell
192 if (!mesh_.isInternalFace(faceI))
194 FatalErrorIn("sameDualCell(const label, const label)")
195 << "face:" << faceI << " is not internal face."
196 << abort(FatalError);
199 label own = mesh_.faceOwner()[faceI];
200 label nei = mesh_.faceNeighbour()[faceI];
202 return findDualCell(own, pointI) == findDualCell(nei, pointI);
206 Foam::label Foam::meshDualiser::addInternalFace
208 const label masterPointI,
209 const label masterEdgeI,
210 const label masterFaceI,
212 const bool edgeOrder,
213 const label dualCell0,
214 const label dualCell1,
215 const DynamicList<label>& verts,
216 directTopoChange& meshMod
221 if (edgeOrder != (dualCell0 < dualCell1))
228 pointField facePoints(meshMod.points(), newFace);
231 pointField newPoints;
232 bool hasMerged = mergePoints
243 FatalErrorIn("addInternalFace(..)")
244 << "verts:" << verts << " newFace:" << newFace
245 << " face points:" << facePoints
246 << abort(FatalError);
252 bool zoneFlip = false;
253 if (masterFaceI != -1)
255 zoneID = mesh_.faceZones().whichZone(masterFaceI);
259 const faceZone& fZone = mesh_.faceZones()[zoneID];
261 zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
267 if (dualCell0 < dualCell1)
269 dualFaceI = meshMod.addFace
274 masterPointI, // masterPointID
275 masterEdgeI, // masterEdgeID
276 masterFaceI, // masterFaceID
277 false, // flipFaceFlux
283 //pointField dualPoints(meshMod.points());
284 //vector n(newFace.normal(dualPoints));
286 //Pout<< "Generated internal dualFace:" << dualFaceI
287 // << " verts:" << newFace
288 // << " points:" << UIndirectList<point>(meshMod.points(), newFace)()
290 // << " between dualowner:" << dualCell0
291 // << " dualneigbour:" << dualCell1
296 dualFaceI = meshMod.addFace
301 masterPointI, // masterPointID
302 masterEdgeI, // masterEdgeID
303 masterFaceI, // masterFaceID
304 false, // flipFaceFlux
310 //pointField dualPoints(meshMod.points());
311 //vector n(newFace.normal(dualPoints));
313 //Pout<< "Generated internal dualFace:" << dualFaceI
314 // << " verts:" << newFace
315 // << " points:" << UIndirectList<point>(meshMod.points(), newFace)()
317 // << " between dualowner:" << dualCell1
318 // << " dualneigbour:" << dualCell0
325 Foam::label Foam::meshDualiser::addBoundaryFace
327 const label masterPointI,
328 const label masterEdgeI,
329 const label masterFaceI,
331 const label dualCellI,
333 const DynamicList<label>& verts,
334 directTopoChange& meshMod
340 bool zoneFlip = false;
341 if (masterFaceI != -1)
343 zoneID = mesh_.faceZones().whichZone(masterFaceI);
347 const faceZone& fZone = mesh_.faceZones()[zoneID];
349 zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
353 label dualFaceI = meshMod.addFace
358 masterPointI, // masterPointID
359 masterEdgeI, // masterEdgeID
360 masterFaceI, // masterFaceID
361 false, // flipFaceFlux
367 //pointField dualPoints(meshMod.points());
368 //vector n(newFace.normal(dualPoints));
370 //Pout<< "Generated boundary dualFace:" << dualFaceI
371 // << " verts:" << newFace
372 // << " points:" << UIndirectList<point>(meshMod.points(), newFace)()
374 // << " on dualowner:" << dualCellI
380 // Walks around edgeI.
381 // splitFace=true : creates multiple faces
382 // splitFace=false: creates single face if same dual cells on both sides,
383 // multiple faces otherwise.
384 void Foam::meshDualiser::createFacesAroundEdge
386 const bool splitFace,
387 const PackedBoolList& isBoundaryEdge,
389 const label startFaceI,
390 directTopoChange& meshMod,
394 const edge& e = mesh_.edges()[edgeI];
395 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
397 label fp = edgeFaceCirculator::getMinIndex
399 mesh_.faces()[startFaceI],
404 edgeFaceCirculator ie
410 isBoundaryEdge.get(edgeI) == 1 // isBoundaryEdge
414 bool edgeOrder = ie.sameOrder(e[0], e[1]);
415 label startFaceLabel = ie.faceLabel();
417 //Pout<< "At edge:" << edgeI << " verts:" << e
418 // << " points:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
419 // << " started walking at face:" << ie.faceLabel()
420 // << " verts:" << mesh_.faces()[ie.faceLabel()]
421 // << " edgeOrder:" << edgeOrder
422 // << " in direction of cell:" << ie.cellLabel()
425 // Walk and collect face.
426 DynamicList<label> verts(100);
428 if (edgeToDualPoint_[edgeI] != -1)
430 verts.append(edgeToDualPoint_[edgeI]);
432 if (faceToDualPoint_[ie.faceLabel()] != -1)
434 doneEFaces[findIndex(eFaces, ie.faceLabel())] = true;
435 verts.append(faceToDualPoint_[ie.faceLabel()]);
437 if (cellToDualPoint_[ie.cellLabel()] != -1)
439 verts.append(cellToDualPoint_[ie.cellLabel()]);
442 label currentDualCell0 = findDualCell(ie.cellLabel(), e[0]);
443 label currentDualCell1 = findDualCell(ie.cellLabel(), e[1]);
449 label faceI = ie.faceLabel();
451 // Mark face as visited.
452 doneEFaces[findIndex(eFaces, faceI)] = true;
454 if (faceToDualPoint_[faceI] != -1)
456 verts.append(faceToDualPoint_[faceI]);
459 label cellI = ie.cellLabel();
463 // At ending boundary face. We've stored the face point above
464 // so this is the whole face.
469 label dualCell0 = findDualCell(cellI, e[0]);
470 label dualCell1 = findDualCell(cellI, e[1]);
472 // Generate face. (always if splitFace=true; only if needed to
473 // separate cells otherwise)
478 dualCell0 != currentDualCell0
479 || dualCell1 != currentDualCell1
483 // Close current face.
487 edgeI, // masterEdgeI
497 currentDualCell0 = dualCell0;
498 currentDualCell1 = dualCell1;
501 if (edgeToDualPoint_[edgeI] != -1)
503 verts.append(edgeToDualPoint_[edgeI]);
505 if (faceToDualPoint_[faceI] != -1)
507 verts.append(faceToDualPoint_[faceI]);
511 if (cellToDualPoint_[cellI] != -1)
513 verts.append(cellToDualPoint_[cellI]);
520 // Back at start face (for internal edge only). See if this needs
522 if (isBoundaryEdge.get(edgeI) == 0)
524 label startDual = faceToDualPoint_[startFaceLabel];
526 if (startDual != -1 && findIndex(verts, startDual) == -1)
528 verts.append(startDual);
539 edgeI, // masterEdgeI
550 // Walks around circumference of faceI. Creates single face. Gets given
551 // starting (feature) edge to start from. Returns ending edge. (all edges
552 // in form of index in faceEdges)
553 void Foam::meshDualiser::createFaceFromInternalFace
557 directTopoChange& meshMod
560 const face& f = mesh_.faces()[faceI];
561 const labelList& fEdges = mesh_.faceEdges()[faceI];
562 label own = mesh_.faceOwner()[faceI];
563 label nei = mesh_.faceNeighbour()[faceI];
565 //Pout<< "createFaceFromInternalFace : At face:" << faceI
567 // << " points:" << UIndirectList<point>(mesh_.points(), f)()
568 // << " started walking at edge:" << fEdges[fp]
569 // << " verts:" << mesh_.edges()[fEdges[fp]]
573 // Walk and collect face.
574 DynamicList<label> verts(100);
576 verts.append(faceToDualPoint_[faceI]);
577 verts.append(edgeToDualPoint_[fEdges[fp]]);
579 // Step to vertex after edge mid
582 // Get cells on either side of face at that point
583 label currentDualCell0 = findDualCell(own, f[fp]);
584 label currentDualCell1 = findDualCell(nei, f[fp]);
589 if (pointToDualPoint_[f[fp]] != -1)
591 verts.append(pointToDualPoint_[f[fp]]);
594 // Edge between fp and fp+1
595 label edgeI = fEdges[fp];
597 if (edgeToDualPoint_[edgeI] != -1)
599 verts.append(edgeToDualPoint_[edgeI]);
602 // Next vertex on edge
603 label nextFp = f.fcIndex(fp);
605 // Get dual cells on nextFp to check whether face needs closing.
606 label dualCell0 = findDualCell(own, f[nextFp]);
607 label dualCell1 = findDualCell(nei, f[nextFp]);
609 if (dualCell0 != currentDualCell0 || dualCell1 != currentDualCell1)
611 // Check: make sure that there is a midpoint on the edge.
612 if (edgeToDualPoint_[edgeI] == -1)
614 FatalErrorIn("createFacesFromInternalFace(..)")
615 << "face:" << faceI << " verts:" << f
616 << " points:" << UIndirectList<point>(mesh_.points(), f)()
617 << " no feature edge between " << f[fp]
618 << " and " << f[nextFp] << " although have different"
619 << " dual cells." << endl
620 << "point " << f[fp] << " has dual cells "
621 << currentDualCell0 << " and " << currentDualCell1
622 << " ; point "<< f[nextFp] << " has dual cells "
623 << dualCell0 << " and " << dualCell1
624 << abort(FatalError);
628 // Close current face.
634 faceI, // masterFaceI
649 // Given a point on a face converts the faces around the point.
650 // (pointFaces()). Gets starting face and marks off visited faces in donePFaces.
651 void Foam::meshDualiser::createFacesAroundBoundaryPoint
654 const label patchPointI,
655 const label startFaceI,
656 directTopoChange& meshMod,
657 boolList& donePFaces // pFaces visited
660 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
661 const polyPatch& pp = patches[patchI];
662 const labelList& pFaces = pp.pointFaces()[patchPointI];
663 const labelList& own = mesh_.faceOwner();
665 label pointI = pp.meshPoints()[patchPointI];
667 if (pointToDualPoint_[pointI] == -1)
669 // Not a feature point. Loop over all connected
673 label faceI = startFaceI;
675 DynamicList<label> verts(4);
679 label index = findIndex(pFaces, faceI-pp.start());
681 // Has face been visited already?
682 if (donePFaces[index])
686 donePFaces[index] = true;
688 // Insert face centre
689 verts.append(faceToDualPoint_[faceI]);
691 label dualCellI = findDualCell(own[faceI], pointI);
693 // Get the edge before the patchPointI
694 const face& f = mesh_.faces()[faceI];
695 label fp = findIndex(f, pointI);
696 label prevFp = f.rcIndex(fp);
697 label edgeI = mesh_.faceEdges()[faceI][prevFp];
699 if (edgeToDualPoint_[edgeI] != -1)
701 verts.append(edgeToDualPoint_[edgeI]);
704 // Get next boundary face (whilst staying on edge).
705 edgeFaceCirculator circ
710 prevFp, // index of edge in face
711 true // isBoundaryEdge
718 while (mesh_.isInternalFace(circ.faceLabel()));
721 faceI = circ.faceLabel();
723 if (faceI < pp.start() || faceI >= pp.start()+pp.size())
727 "meshDualiser::createFacesAroundBoundaryPoint(..)"
728 ) << "Walked from face on patch:" << patchI
729 << " to face:" << faceI
730 << " fc:" << mesh_.faceCentres()[faceI]
731 << " on patch:" << patches.whichPatch(faceI)
732 << abort(FatalError);
735 // Check if different cell.
736 if (dualCellI != findDualCell(own[faceI], pointI))
740 "meshDualiser::createFacesAroundBoundaryPoint(..)"
741 ) << "Different dual cells but no feature edge"
742 << " inbetween point:" << pointI
743 << " coord:" << mesh_.points()[pointI]
744 << abort(FatalError);
750 label dualCellI = findDualCell(own[faceI], pointI);
752 //Bit dodgy: create dualface from the last face (instead of from
753 // the central point). This will also use the original faceZone to
754 // put the new face (which might span multiple original faces) in.
758 //pointI, // masterPointI
761 faceI, // masterFaceI
770 label faceI = startFaceI;
773 DynamicList<label> verts(mesh_.faces()[faceI].size());
776 verts.append(pointToDualPoint_[pointI]);
778 // Find edge between pointI and next point on face.
779 const labelList& fEdges = mesh_.faceEdges()[faceI];
780 label nextEdgeI = fEdges[findIndex(mesh_.faces()[faceI], pointI)];
781 if (edgeToDualPoint_[nextEdgeI] != -1)
783 verts.append(edgeToDualPoint_[nextEdgeI]);
788 label index = findIndex(pFaces, faceI-pp.start());
790 // Has face been visited already?
791 if (donePFaces[index])
795 donePFaces[index] = true;
798 verts.append(faceToDualPoint_[faceI]);
800 // Find edge before pointI on faceI
801 const labelList& fEdges = mesh_.faceEdges()[faceI];
802 const face& f = mesh_.faces()[faceI];
803 label prevFp = f.rcIndex(findIndex(f, pointI));
804 label edgeI = fEdges[prevFp];
806 if (edgeToDualPoint_[edgeI] != -1)
808 // Feature edge. Close any face so far. Note: uses face to
809 // create dualFace from. Could use pointI instead.
810 verts.append(edgeToDualPoint_[edgeI]);
815 faceI, // masterFaceI
816 findDualCell(own[faceI], pointI),
823 verts.append(pointToDualPoint_[pointI]);
824 verts.append(edgeToDualPoint_[edgeI]);
827 // Cross edgeI to next boundary face
828 edgeFaceCirculator circ
833 prevFp, // index of edge in face
834 true // isBoundaryEdge
841 while (mesh_.isInternalFace(circ.faceLabel()));
843 // Step to next face. Quit if not on same patch.
844 faceI = circ.faceLabel();
849 && faceI >= pp.start()
850 && faceI < pp.start()+pp.size()
853 if (verts.size() > 2)
855 // Note: face created from face, not from pointI
860 startFaceI, // masterFaceI
861 findDualCell(own[faceI], pointI),
871 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
873 Foam::meshDualiser::meshDualiser(const polyMesh& mesh)
876 pointToDualCells_(mesh_.nPoints()),
877 pointToDualPoint_(mesh_.nPoints(), -1),
878 cellToDualPoint_(mesh_.nCells()),
879 faceToDualPoint_(mesh_.nFaces(), -1),
880 edgeToDualPoint_(mesh_.nEdges(), -1)
884 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
887 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
889 void Foam::meshDualiser::setRefinement
891 const bool splitFace,
892 const labelList& featureFaces,
893 const labelList& featureEdges,
894 const labelList& singleCellFeaturePoints,
895 const labelList& multiCellFeaturePoints,
896 directTopoChange& meshMod
899 const labelList& own = mesh_.faceOwner();
900 const labelList& nei = mesh_.faceNeighbour();
901 const vectorField& cellCentres = mesh_.cellCentres();
903 // Mark boundary edges and points.
904 // (Note: in 1.4.2 we can use the built-in mesh point ordering
906 PackedBoolList isBoundaryEdge(mesh_.nEdges());
907 for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
909 const labelList& fEdges = mesh_.faceEdges()[faceI];
913 isBoundaryEdge.set(fEdges[i], 1);
920 // This is a special mode where whenever we are walking around an edge
921 // every area through a cell becomes a separate dualface. So two
922 // dual cells will probably have more than one dualface between them!
923 // This mode implies that
924 // - all faces have to be feature faces since there has to be a
925 // dualpoint at the face centre.
926 // - all edges have to be feature edges ,,
927 boolList featureFaceSet(mesh_.nFaces(), false);
928 forAll(featureFaces, i)
930 featureFaceSet[featureFaces[i]] = true;
932 label faceI = findIndex(featureFaceSet, false);
938 "meshDualiser::setRefinement"
939 "(const labelList&, const labelList&, const labelList&"
940 ", const labelList, directTopoChange&)"
941 ) << "In split-face-mode (splitFace=true) but not all faces"
942 << " marked as feature faces." << endl
943 << "First conflicting face:" << faceI
944 << " centre:" << mesh_.faceCentres()[faceI]
945 << abort(FatalError);
948 boolList featureEdgeSet(mesh_.nEdges(), false);
949 forAll(featureEdges, i)
951 featureEdgeSet[featureEdges[i]] = true;
953 label edgeI = findIndex(featureEdgeSet, false);
957 const edge& e = mesh_.edges()[edgeI];
960 "meshDualiser::setRefinement"
961 "(const labelList&, const labelList&, const labelList&"
962 ", const labelList, directTopoChange&)"
963 ) << "In split-face-mode (splitFace=true) but not all edges"
964 << " marked as feature edges." << endl
965 << "First conflicting edge:" << edgeI
967 << " coords:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
968 << abort(FatalError);
973 // Check that all boundary faces are feature faces.
975 boolList featureFaceSet(mesh_.nFaces(), false);
976 forAll(featureFaces, i)
978 featureFaceSet[featureFaces[i]] = true;
982 label faceI = mesh_.nInternalFaces();
983 faceI < mesh_.nFaces();
987 if (!featureFaceSet[faceI])
991 "meshDualiser::setRefinement"
992 "(const labelList&, const labelList&, const labelList&"
993 ", const labelList, directTopoChange&)"
994 ) << "Not all boundary faces marked as feature faces."
996 << "First conflicting face:" << faceI
997 << " centre:" << mesh_.faceCentres()[faceI]
998 << abort(FatalError);
1006 // Start creating cells, points, and faces (in that order)
1009 // 1. Mark which cells to create
1010 // Mostly every point becomes one cell but sometimes (for feature points)
1011 // all cells surrounding a feature point become cells. Also a non-manifold
1012 // point can create two cells! So a dual cell is uniquely defined by a
1013 // mesh point + cell (as in pointCells index)
1015 // 2. Mark which face centres to create
1017 // 3. Internal faces can now consist of
1018 // - only cell centres of walk around edge
1019 // - cell centres + face centres of walk around edge
1020 // - same but now other side is not a single cell
1022 // 4. Boundary faces (or internal faces between cell zones!) now consist of
1023 // - walk around boundary point.
1027 autoPtr<OFstream> dualCcStr;
1030 dualCcStr.reset(new OFstream("dualCc.obj"));
1031 Pout<< "Dumping centres of dual cells to " << dualCcStr().name()
1036 // Dual cells (from points)
1037 // ~~~~~~~~~~~~~~~~~~~~~~~~
1039 // pointToDualCells_[pointI]
1040 // - single entry : all cells surrounding point all become the same
1042 // - multiple entries: in order of pointCells.
1045 // feature points that become single cell
1046 forAll(singleCellFeaturePoints, i)
1048 label pointI = singleCellFeaturePoints[i];
1050 pointToDualPoint_[pointI] = meshMod.addPoint
1052 mesh_.points()[pointI],
1053 pointI, // masterPoint
1054 mesh_.pointZones().whichZone(pointI), // zoneID
1058 // Generate single cell
1059 pointToDualCells_[pointI].setSize(1);
1060 pointToDualCells_[pointI][0] = meshMod.addCell
1062 pointI, //masterPointID,
1068 if (dualCcStr.valid())
1070 meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointI]);
1074 // feature points that become multiple cells
1075 forAll(multiCellFeaturePoints, i)
1077 label pointI = multiCellFeaturePoints[i];
1079 if (pointToDualCells_[pointI].size() > 0)
1083 "meshDualiser::setRefinement"
1084 "(const labelList&, const labelList&, const labelList&"
1085 ", const labelList, directTopoChange&)"
1086 ) << "Point " << pointI << " at:" << mesh_.points()[pointI]
1087 << " is both in singleCellFeaturePoints"
1088 << " and multiCellFeaturePoints."
1089 << abort(FatalError);
1092 pointToDualPoint_[pointI] = meshMod.addPoint
1094 mesh_.points()[pointI],
1095 pointI, // masterPoint
1096 mesh_.pointZones().whichZone(pointI), // zoneID
1100 // Create dualcell for every cell connected to dual point
1102 const labelList& pCells = mesh_.pointCells()[pointI];
1104 pointToDualCells_[pointI].setSize(pCells.size());
1106 forAll(pCells, pCellI)
1108 pointToDualCells_[pointI][pCellI] = meshMod.addCell
1110 pointI, //masterPointID
1114 mesh_.cellZones().whichZone(pCells[pCellI]) //zoneID
1116 if (dualCcStr.valid())
1121 0.5*(mesh_.points()[pointI]+cellCentres[pCells[pCellI]])
1127 forAll(mesh_.points(), pointI)
1129 if (pointToDualCells_[pointI].empty())
1131 pointToDualCells_[pointI].setSize(1);
1132 pointToDualCells_[pointI][0] = meshMod.addCell
1134 pointI, //masterPointID,
1141 if (dualCcStr.valid())
1143 meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointI]);
1149 // Dual points (from cell centres, feature faces, feature edges)
1150 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1152 forAll(cellToDualPoint_, cellI)
1154 cellToDualPoint_[cellI] = meshMod.addPoint
1157 mesh_.faces()[mesh_.cells()[cellI][0]][0], // masterPoint
1163 // From face to dual point
1165 forAll(featureFaces, i)
1167 label faceI = featureFaces[i];
1169 faceToDualPoint_[faceI] = meshMod.addPoint
1171 mesh_.faceCentres()[faceI],
1172 mesh_.faces()[faceI][0], // masterPoint
1177 // Detect whether different dual cells on either side of a face. This
1178 // would neccesitate having a dual face built from the face and thus a
1179 // dual point at the face centre.
1180 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1182 if (faceToDualPoint_[faceI] == -1)
1184 const face& f = mesh_.faces()[faceI];
1188 label ownDualCell = findDualCell(own[faceI], f[fp]);
1189 label neiDualCell = findDualCell(nei[faceI], f[fp]);
1191 if (ownDualCell != neiDualCell)
1193 faceToDualPoint_[faceI] = meshMod.addPoint
1195 mesh_.faceCentres()[faceI],
1196 f[fp], // masterPoint
1207 // From edge to dual point
1209 forAll(featureEdges, i)
1211 label edgeI = featureEdges[i];
1213 const edge& e = mesh_.edges()[edgeI];
1215 edgeToDualPoint_[edgeI] = meshMod.addPoint
1217 e.centre(mesh_.points()),
1218 e[0], // masterPoint
1224 // Detect whether different dual cells on either side of an edge. This
1225 // would neccesitate having a dual face built perpendicular to the edge
1226 // and thus a dual point at the mid of the edge.
1227 // Note: not really true - the face can be built without the edge centre!
1228 const labelListList& edgeCells = mesh_.edgeCells();
1230 forAll(edgeCells, edgeI)
1232 if (edgeToDualPoint_[edgeI] == -1)
1234 const edge& e = mesh_.edges()[edgeI];
1236 // We need a point on the edge if not all cells on both sides
1239 const labelList& eCells = mesh_.edgeCells()[edgeI];
1241 label dualE0 = findDualCell(eCells[0], e[0]);
1242 label dualE1 = findDualCell(eCells[0], e[1]);
1244 for (label i = 1; i < eCells.size(); i++)
1246 label newDualE0 = findDualCell(eCells[i], e[0]);
1248 if (dualE0 != newDualE0)
1250 edgeToDualPoint_[edgeI] = meshMod.addPoint
1252 e.centre(mesh_.points()),
1253 e[0], // masterPoint
1254 mesh_.pointZones().whichZone(e[0]), // zoneID
1261 label newDualE1 = findDualCell(eCells[i], e[1]);
1263 if (dualE1 != newDualE1)
1265 edgeToDualPoint_[edgeI] = meshMod.addPoint
1267 e.centre(mesh_.points()),
1268 e[1], // masterPoint
1269 mesh_.pointZones().whichZone(e[1]), // zoneID
1279 // Make sure all boundary edges emanating from feature points are
1280 // feature edges as well.
1281 forAll(singleCellFeaturePoints, i)
1283 generateDualBoundaryEdges
1286 singleCellFeaturePoints[i],
1290 forAll(multiCellFeaturePoints, i)
1292 generateDualBoundaryEdges
1295 multiCellFeaturePoints[i],
1301 // Check for duplicate points
1304 dumpPolyTopoChange(meshMod, "generatedPoints_");
1305 checkPolyTopoChange(meshMod);
1309 // Now we have all points and cells
1310 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1311 // - pointToDualCells_ : per point a single dualCell or multiple dualCells
1312 // - pointToDualPoint_ : per point -1 or the dual point at the coordinate
1313 // - edgeToDualPoint_ : per edge -1 or the edge centre
1314 // - faceToDualPoint_ : per face -1 or the face centre
1315 // - cellToDualPoint_ : per cell the cell centre
1316 // Now we have to walk all edges and construct faces. Either single face
1317 // per edge or multiple (-if nonmanifold edge -if different dualcells)
1319 const edgeList& edges = mesh_.edges();
1321 forAll(edges, edgeI)
1323 const labelList& eFaces = mesh_.edgeFaces()[edgeI];
1325 boolList doneEFaces(eFaces.size(), false);
1331 // We found a face that hasn't yet been visited. This might
1332 // happen for non-manifold edges where a single edge can
1333 // become multiple faces.
1335 label startFaceI = eFaces[i];
1337 //Pout<< "Walking edge:" << edgeI
1338 // << " points:" << mesh_.points()[e[0]]
1339 // << mesh_.points()[e[1]]
1340 // << " startFace:" << startFaceI
1341 // << " at:" << mesh_.faceCentres()[startFaceI]
1344 createFacesAroundEdge
1359 dumpPolyTopoChange(meshMod, "generatedFacesFromEdges_");
1362 // Create faces from feature faces. These can be internal or external faces.
1363 // - feature face : centre needs to be included.
1364 // - single cells on either side: triangulate
1365 // - multiple cells: create single face between unique cell pair. Only
1366 // create face where cells differ on either side.
1367 // - non-feature face : inbetween cell zones.
1368 forAll(faceToDualPoint_, faceI)
1370 if (faceToDualPoint_[faceI] != -1 && mesh_.isInternalFace(faceI))
1372 const face& f = mesh_.faces()[faceI];
1373 const labelList& fEdges = mesh_.faceEdges()[faceI];
1380 // Find edge that is in dual mesh and where the
1381 // next point (fp+1) has different dual cells on either side.
1382 bool foundStart = false;
1388 edgeToDualPoint_[fEdges[fp]] != -1
1389 && !sameDualCell(faceI, f.nextLabel(fp))
1404 // Walk from edge fp and generate a face.
1405 createFaceFromInternalFace
1418 dumpPolyTopoChange(meshMod, "generatedFacesFromFeatFaces_");
1422 // Create boundary faces. Every boundary point has one or more dualcells.
1423 // These need to be closed.
1424 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1426 forAll(patches, patchI)
1428 const polyPatch& pp = patches[patchI];
1430 const labelListList& pointFaces = pp.pointFaces();
1432 forAll(pointFaces, patchPointI)
1434 const labelList& pFaces = pointFaces[patchPointI];
1436 boolList donePFaces(pFaces.size(), false);
1443 label startFaceI = pp.start()+pFaces[i];
1445 //Pout<< "Walking around point:" << pointI
1446 // << " coord:" << mesh_.points()[pointI]
1447 // << " on patch:" << patchI
1448 // << " startFace:" << startFaceI
1449 // << " at:" << mesh_.faceCentres()[startFaceI]
1452 createFacesAroundBoundaryPoint
1458 donePFaces // pFaces visited
1467 dumpPolyTopoChange(meshMod, "generatedFacesFromBndFaces_");
1473 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1476 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
1479 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
1482 // ************************************************************************* //