1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh 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 cfMesh 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 cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "polyMeshGenModifier.H"
29 #include "demandDrivenData.H"
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 void polyMeshGenModifier::zipUpCells()
46 Info<< "Zipping up topologically open cells" << endl;
48 const pointFieldPMG& points = mesh_.points();
49 const cellListPMG& cells = mesh_.cells();
51 faceListPMG& faces = mesh_.faces_;
54 // Take the original mesh and visit all cells. For every cell
55 // calculate the edges of all faces on the cells. A cell is
56 // correctly topologically closed when all the edges are reference
57 // by exactly two cells. If the edges are referenced only by a
58 // single cell, additional vertices need to be inserted into some
59 // of the faces (topological closedness). If an edge is
60 // referenced by more that two faces, there is an error in
61 // topological closedness.
62 // Point insertion into the faces is done by attempting to create
63 // closed loops and inserting the intermediate points into the
66 // The algorithm is recursive and changes the mesh faces in each
67 // pass. It is therefore essential to discard the addressing
68 // after every pass. The algorithm is completed when the mesh
72 label nChangedFacesInMesh;
75 labelHashSet problemCells;
79 nChangedFacesInMesh = 0;
81 //- calculate pointFaces addressing
83 Info << "Starting pointFaces addressing " << endl;
86 List<direction> nUsage(points.size(), direction(0));
89 const face& f = faces[fI];
94 VRWGraph pFaces(points.size());
96 pFaces.setRowSize(pI, nUsage[pI]);
102 const face& f = faces[fI];
104 pFaces(f[pI], nUsage[f[pI]]++) = fI;
110 Info << "Starting zipping cells " << endl;
113 forAll (cells, cellI)
115 const labelList& curFaces = cells[cellI];
116 const edgeList cellEdges = cells[cellI].edges(faces);
117 const labelList cellPoints = cells[cellI].labels(faces);
119 // Find the edges used only once in the cell
121 labelList edgeUsage(cellEdges.size(), 0);
123 forAll (curFaces, faceI)
125 edgeList curFaceEdges = faces[curFaces[faceI]].edges();
127 forAll (curFaceEdges, faceEdgeI)
129 const edge& curEdge = curFaceEdges[faceEdgeI];
131 forAll (cellEdges, cellEdgeI)
133 if (cellEdges[cellEdgeI] == curEdge)
135 edgeUsage[cellEdgeI]++;
142 edgeList singleEdges(cellEdges.size());
143 label nSingleEdges = 0;
145 forAll (edgeUsage, edgeI)
147 if (edgeUsage[edgeI] == 1)
149 singleEdges[nSingleEdges] = cellEdges[edgeI];
152 else if (edgeUsage[edgeI] != 2)
155 << "void polyMesh::zipUpCells() : "
156 << "edge " << cellEdges[edgeI] << " in cell " << cellI
157 << " used " << edgeUsage[edgeI] << " times. " << nl
158 << "Should be 1 or 2 - serious error "
159 << "in mesh structure. " << endl;
162 forAll (curFaces, faceI)
164 Info<< "face: " << faces[curFaces[faceI]]
168 Info<< "Cell edges: " << cellEdges << nl
169 << "Edge usage: " << edgeUsage << nl
170 << "Cell points: " << cellPoints << endl;
172 forAll (cellPoints, cpI)
174 Info<< "vertex create \"" << cellPoints[cpI]
176 << points[cellPoints[cpI]] << endl;
180 // Gather the problem cell
181 problemCells.insert(cellI);
185 // Check if the cell is already zipped up
186 if (nSingleEdges == 0) continue;
188 singleEdges.setSize(nSingleEdges);
191 Info << "Cell " << cellI << endl;
193 forAll (curFaces, faceI)
195 Info<< "face: " << faces[curFaces[faceI]] << endl;
198 Info<< "Cell edges: " << cellEdges << nl
199 << "Edge usage: " << edgeUsage << nl
200 << "Single edges: " << singleEdges << nl
201 << "Cell points: " << cellPoints << endl;
203 forAll (cellPoints, cpI)
205 Info<< "vertex create \"" << cellPoints[cpI]
207 << points[cellPoints[cpI]] << endl;
211 // Loop through all single edges and mark the points they use
212 // points marked twice are internal to edge; those marked more than
215 labelList pointUsage(cellPoints.size(), 0);
217 forAll (singleEdges, edgeI)
219 const edge& curEdge = singleEdges[edgeI];
221 forAll (cellPoints, pointI)
225 cellPoints[pointI] == curEdge.start()
226 || cellPoints[pointI] == curEdge.end()
229 pointUsage[pointI]++;
234 boolList singleEdgeUsage(singleEdges.size(), false);
236 // loop through all edges and eliminate the ones that are
238 forAll (singleEdges, edgeI)
240 bool blockedHead = false;
241 bool blockedTail = false;
243 label newEdgeStart = singleEdges[edgeI].start();
244 label newEdgeEnd = singleEdges[edgeI].end();
246 // check that the edge has not got all ends blocked
247 forAll (cellPoints, pointI)
249 if (cellPoints[pointI] == newEdgeStart)
251 if (pointUsage[pointI] > 2)
256 else if (cellPoints[pointI] == newEdgeEnd)
258 if (pointUsage[pointI] > 2)
265 if (blockedHead && blockedTail)
267 // Eliminating edge singleEdges[edgeI] as blocked
268 singleEdgeUsage[edgeI] = true;
272 // Go through the points and start from the point used twice
273 // check all the edges to find the edges starting from this point
276 labelListList edgesToInsert(singleEdges.size());
277 label nEdgesToInsert = 0;
280 forAll (singleEdges, edgeI)
282 SLList<label> pointChain;
284 bool blockHead = false;
285 bool blockTail = false;
287 if (!singleEdgeUsage[edgeI])
290 singleEdgeUsage[edgeI] = true;
292 label newEdgeStart = singleEdges[edgeI].start();
293 label newEdgeEnd = singleEdges[edgeI].end();
295 pointChain.insert(newEdgeStart);
296 pointChain.append(newEdgeEnd);
299 Info<< "found edge to start with: "
300 << singleEdges[edgeI] << endl;
303 // Check if head or tail are blocked
304 forAll (cellPoints, pointI)
306 if (cellPoints[pointI] == newEdgeStart)
308 if (pointUsage[pointI] > 2)
311 Info << "start head blocked" << endl;
317 else if(cellPoints[pointI] == newEdgeEnd)
319 if (pointUsage[pointI] > 2)
322 Info << "start tail blocked" << endl;
330 bool stopSearching = false;
332 // Go through the unused edges and try to chain them up
335 stopSearching = false;
337 forAll (singleEdges, addEdgeI)
339 if (!singleEdgeUsage[addEdgeI])
341 // Grab start and end of the candidate
343 singleEdges[addEdgeI].start();
346 singleEdges[addEdgeI].end();
349 Info<< "Trying candidate "
350 << singleEdges[addEdgeI] << endl;
353 // Try to add the edge onto the head
356 if (pointChain.first() == addStart)
358 // Added at start mark as used
359 pointChain.insert(addEnd);
361 singleEdgeUsage[addEdgeI] = true;
363 else if (pointChain.first() == addEnd)
365 pointChain.insert(addStart);
367 singleEdgeUsage[addEdgeI] = true;
371 // Try the other end only if the first end
373 if (!blockTail && !singleEdgeUsage[addEdgeI])
375 if (pointChain.last() == addStart)
377 // Added at start mark as used
378 pointChain.append(addEnd);
380 singleEdgeUsage[addEdgeI] = true;
382 else if (pointChain.last() == addEnd)
384 pointChain.append(addStart);
386 singleEdgeUsage[addEdgeI] = true;
390 // check if the new head or tail are blocked
391 label curEdgeStart = pointChain.first();
392 label curEdgeEnd = pointChain.last();
395 Info<< "curEdgeStart: " << curEdgeStart
396 << " curEdgeEnd: " << curEdgeEnd << endl;
399 forAll (cellPoints, pointI)
401 if (cellPoints[pointI] == curEdgeStart)
403 if (pointUsage[pointI] > 2)
406 Info << "head blocked" << endl;
412 else if(cellPoints[pointI] == curEdgeEnd)
414 if (pointUsage[pointI] > 2)
417 Info << "tail blocked" << endl;
425 // Check if the loop is closed
426 if (curEdgeStart == curEdgeEnd)
429 Info << "closed loop" << endl;
432 pointChain.removeHead();
437 stopSearching = true;
441 Info<< "current pointChain: " << pointChain
445 if (stopSearching) break;
448 } while (stopSearching);
452 Info << "completed patch chain: " << pointChain << endl;
455 if (pointChain.size() > 2)
457 edgesToInsert[nEdgesToInsert] = pointChain;
462 edgesToInsert.setSize(nEdgesToInsert);
465 Info << "edgesToInsert: " << edgesToInsert << endl;
468 // Insert the edges into a list of faces
469 forAll (edgesToInsert, edgeToInsertI)
471 // Order the points of the edge
472 // Warning: the ordering must be parametric, because in
473 // the case of multiple point insertion onto the same edge
474 // it is possible to get non-cyclic loops
477 const labelList& unorderedEdge = edgesToInsert[edgeToInsertI];
479 scalarField dist(unorderedEdge.size());
481 // Calculate distance
482 point startPoint = points[unorderedEdge[0]];
486 points[unorderedEdge[unorderedEdge.size() - 1]]
489 for (label i = 1; i < dist.size(); i++)
491 dist[i] = (points[unorderedEdge[i]] - startPoint) & dir;
495 labelList orderedEdge(unorderedEdge.size(), -1);
496 boolList used(unorderedEdge.size(), false);
498 forAll (orderedEdge, epI)
500 label nextPoint = -1;
501 scalar minDist = GREAT;
505 if (!used[i] && dist[i] < minDist)
512 // Insert the next point
513 orderedEdge[epI] = unorderedEdge[nextPoint];
514 used[nextPoint] = true;
518 Info<< "unorderedEdge: " << unorderedEdge << nl
519 << "orderedEdge: " << orderedEdge << endl;
522 // check for duplicate points in the ordered edge
523 forAll (orderedEdge, checkI)
527 label checkJ = checkI + 1;
528 checkJ < orderedEdge.size();
532 if (orderedEdge[checkI] == orderedEdge[checkJ])
535 << "void polyMesh::zipUpCells() : "
536 << "Duplicate point found in edge to insert. "
537 << nl << "Point: " << orderedEdge[checkI]
538 << " edge: " << orderedEdge << endl;
540 problemCells.insert(cellI);
548 orderedEdge[orderedEdge.size() - 1]
551 // In order to avoid edge-to-edge comparison, get faces using
552 // point-face addressing in two goes.
553 const label start = testEdge.start();
554 const label end = testEdge.end();
556 labelList facesSharingEdge
558 pFaces.sizeOfRow(start) +
559 pFaces.sizeOfRow(end)
563 forAllRow(pFaces, start, pfI)
564 facesSharingEdge[nfse++] = pFaces(start, pfI);
566 forAllRow(pFaces, end, pfI)
567 facesSharingEdge[nfse++] = pFaces(end, pfI);
569 forAll(facesSharingEdge, faceI)
571 bool faceChanges = false;
573 // Label of the face being analysed
574 const label currentFaceIndex = facesSharingEdge[faceI];
576 const edgeList curFaceEdges =
577 faces[currentFaceIndex].edges();
579 forAll (curFaceEdges, cfeI)
581 if (curFaceEdges[cfeI] == testEdge)
590 nChangedFacesInMesh++;
591 // In order to avoid loosing point from multiple
592 // insertions into the same face, the new face
593 // will be change incrementally.
594 // 1) Check if all the internal points of the edge
595 // to add already exist in the face. If so, the
596 // edge has already been included 2) Check if the
597 // point insertion occurs on an edge which is
598 // still untouched. If so, simply insert
599 // additional points into the face. 3) If not,
600 // the edge insertion occurs on an already
601 // modified edge. ???
603 face& newFace = faces[currentFaceIndex];
605 bool allPointsPresent = true;
607 forAll (orderedEdge, oeI)
609 bool curPointFound = false;
611 forAll (newFace, nfI)
613 if (newFace[nfI] == orderedEdge[oeI])
615 curPointFound = true;
621 allPointsPresent && curPointFound;
625 if (allPointsPresent)
627 Info << "All points present" << endl;
631 if (!allPointsPresent)
633 // Not all points are already present. The
634 // new edge will need to be inserted into the
637 // Check to see if a new edge fits onto an
638 // untouched edge of the face. Make sure the
639 // edges are grabbed before the face is
641 edgeList newFaceEdges = newFace.edges();
644 Info << "Not all points present." << endl;
647 label nNewFacePoints = 0;
649 bool edgeAdded = false;
651 forAll (newFaceEdges, curFacEdgI)
653 // Does the current edge change?
654 if (newFaceEdges[curFacEdgI] == testEdge)
656 // Found an edge match
659 // Resize the face to accept additional
664 + orderedEdge.size() - 2
669 newFaceEdges[curFacEdgI].start()
673 // insertion in ascending order
677 i < orderedEdge.size() - 1;
681 newFace[nNewFacePoints] =
688 // insertion in reverse order
691 label i = orderedEdge.size() - 1;
696 newFace[nNewFacePoints] =
704 // Does not fit onto this edge.
705 // Copy the next point into the face
706 newFace[nNewFacePoints] =
707 newFaceEdges[curFacEdgI].start();
721 << faces[currentFaceIndex] << nl
722 << "newFace: " << newFace << endl;
725 // Check for duplicate points in the new face
726 forAll (newFace, checkI)
730 label checkJ = checkI + 1;
731 checkJ < newFace.size();
735 if (newFace[checkI] == newFace[checkJ])
738 << "void polyMesh::zipUpCells()"
739 << "Duplicate point found "
740 << "in the new face. " << nl
742 << orderedEdge[checkI]
746 problemCells.insert(cellI);
751 // Check if the edge is added.
752 // If not, then it comes on top of an already
753 // modified edge and they need to be
754 // merged in together.
757 Info<< "This edge modifies an already modified "
758 << "edge. Point insertions skipped."
767 if (problemCells.size() > 0)
769 // This cycle has failed. Print out the problem cells
770 labelList toc(problemCells.toc());
773 FatalErrorIn("void polyMesh::zipUpCells()")
774 << "Found " << problemCells.size() << " problem cells." << nl
776 << abort(FatalError);
779 Info<< "Cycle " << ++nCycles
780 << " changed " << nChangedFacesInMesh << " faces." << endl;
781 } while (nChangedFacesInMesh > 0 || nCycles > 100);
783 if (nChangedFacesInMesh > 0)
785 FatalErrorIn("void polyMesh::zipUpCells()")
786 << "cell zip-up failed after 100 cycles. Probable problem "
787 << "with the original mesh"
788 << abort(FatalError);
790 Info << "Finished zipping the mesh." << endl;
793 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
795 } // End namespace Foam
797 // ************************************************************************* //