1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
5 \\ / A nd | 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/>.
24 \*---------------------------------------------------------------------------*/
26 #include "objectRegistry.H"
27 #include "cuttingPlane.H"
28 #include "primitiveMesh.H"
29 #include "linePointRef.H"
30 #include "meshTools.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 // set values for what is close to zero and what is considered to
35 // be positive (and not just rounding noise)
37 const Foam::scalar localSmall = Foam::SMALL;
38 const Foam::scalar localSmallPositive = 1e-3*Foam::SMALL;
39 //! @endcond localScope
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 void Foam::cuttingPlane::calcCutCells
46 const primitiveMesh& mesh,
47 const scalarField& dotProducts,
48 const UList<label>& cellIdLabels
51 const labelListList& cellEdges = mesh.cellEdges();
52 const edgeList& edges = mesh.edges();
54 label listSize = cellEdges.size();
55 if (!cellIdLabels.empty())
57 listSize = cellIdLabels.size();
60 cutCells_.setSize(listSize);
63 // Find the cut cells by detecting any cell that uses points with
64 // opposing dotProducts.
65 for (label listI = 0; listI < listSize; ++listI)
68 if (!cellIdLabels.empty())
70 cellI = cellIdLabels[listI];
73 const labelList& cEdges = cellEdges[cellI];
79 const edge& e = edges[cEdges[i]];
84 dotProducts[e[0]] < localSmall
85 && dotProducts[e[1]] > localSmallPositive
88 dotProducts[e[1]] < localSmall
89 && dotProducts[e[0]] > localSmallPositive
97 cutCells_[cutcellI++] = cellI;
105 // Set correct list size
106 cutCells_.setSize(cutcellI);
110 // Determine for each edge the intersection point. Calculates
111 // - cutPoints_ : coordinates of all intersection points
112 // - edgePoint : per edge -1 or the index into cutPoints
113 void Foam::cuttingPlane::intersectEdges
115 const primitiveMesh& mesh,
116 const scalarField& dotProducts,
117 List<label>& edgePoint
120 // Use the dotProducts to find out the cut edges.
121 const edgeList& edges = mesh.edges();
122 const pointField& points = mesh.points();
124 // Per edge -1 or the label of the intersection point
125 edgePoint.setSize(edges.size());
127 DynamicList<point> dynCuttingPoints(4*cutCells_.size());
131 const edge& e = edges[edgeI];
136 dotProducts[e[0]] < localSmall
137 && dotProducts[e[1]] > localSmallPositive
140 dotProducts[e[1]] < localSmall
141 && dotProducts[e[0]] > localSmallPositive
146 edgePoint[edgeI] = dynCuttingPoints.size();
148 const point& p0 = points[e[0]];
149 const point& p1 = points[e[1]];
151 scalar alpha = lineIntersect(linePointRef(p0, p1));
153 if (alpha < localSmall)
155 dynCuttingPoints.append(p0);
157 else if (alpha >= 1.0)
159 dynCuttingPoints.append(p1);
163 dynCuttingPoints.append((1-alpha)*p0 + alpha*p1);
168 edgePoint[edgeI] = -1;
172 this->storedPoints().transfer(dynCuttingPoints);
176 // Coming from startEdgeI cross the edge to the other face
177 // across to the next cut edge.
178 bool Foam::cuttingPlane::walkCell
180 const primitiveMesh& mesh,
181 const UList<label>& edgePoint,
183 const label startEdgeI,
184 DynamicList<label>& faceVerts
188 label edgeI = startEdgeI;
195 faceVerts.append(edgePoint[edgeI]);
197 // Cross edge to other face
198 faceI = meshTools::otherFace(mesh, cellI, faceI, edgeI);
200 // Find next cut edge on face.
201 const labelList& fEdges = mesh.faceEdges()[faceI];
203 label nextEdgeI = -1;
205 //Note: here is where we should check for whether there are more
206 // than 2 intersections with the face (warped/non-convex face).
207 // If so should e.g. decompose the cells on both faces and redo
212 label edge2I = fEdges[i];
214 if (edge2I != edgeI && edgePoint[edge2I] != -1)
223 // Did not find another cut edge on faceI. Do what?
224 WarningIn("Foam::cuttingPlane::walkCell")
225 << "Did not find closed walk along surface of cell " << cellI
226 << " starting from edge " << startEdgeI
227 << " in " << nIter << " iterations." << nl
228 << "Collected cutPoints so far:" << faceVerts
240 WarningIn("Foam::cuttingPlane::walkCell")
241 << "Did not find closed walk along surface of cell " << cellI
242 << " starting from edge " << startEdgeI
243 << " in " << nIter << " iterations." << nl
244 << "Collected cutPoints so far:" << faceVerts
249 } while (edgeI != startEdgeI);
252 if (faceVerts.size() >= 3)
258 WarningIn("Foam::cuttingPlane::walkCell")
259 << "Did not find closed walk along surface of cell " << cellI
260 << " starting from edge " << startEdgeI << nl
261 << "Collected cutPoints so far:" << faceVerts
269 // For every cut cell determine a walk through all? its cuts.
270 void Foam::cuttingPlane::walkCellCuts
272 const primitiveMesh& mesh,
273 const UList<label>& edgePoint
276 const pointField& cutPoints = this->points();
278 // use dynamic lists to handle triangulation and/or missed cuts
279 DynamicList<face> dynCutFaces(cutCells_.size());
280 DynamicList<label> dynCutCells(cutCells_.size());
282 // scratch space for calculating the face vertices
283 DynamicList<label> faceVerts(10);
287 label cellI = cutCells_[i];
289 // Find the starting edge to walk from.
290 const labelList& cEdges = mesh.cellEdges()[cellI];
292 label startEdgeI = -1;
294 forAll(cEdges, cEdgeI)
296 label edgeI = cEdges[cEdgeI];
298 if (edgePoint[edgeI] != -1)
305 // Check for the unexpected ...
306 if (startEdgeI == -1)
308 FatalErrorIn("Foam::cuttingPlane::walkCellCuts")
309 << "Cannot find cut edge for cut cell " << cellI
310 << abort(FatalError);
313 // Walk from starting edge around the circumference of the cell.
314 bool okCut = walkCell
327 // Orient face to point in the same direction as the plane normal
328 if ((f.normal(cutPoints) && normal()) < 0)
333 // the cut faces are usually quite ugly, so always triangulate
334 label nTri = f.triangles(cutPoints, dynCutFaces);
337 dynCutCells.append(cellI);
342 this->storedFaces().transfer(dynCutFaces);
343 cutCells_.transfer(dynCutCells);
347 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
349 // Construct without cutting
350 Foam::cuttingPlane::cuttingPlane(const plane& pln)
356 // Construct from plane and mesh reference, restricted to a list of cells
357 Foam::cuttingPlane::cuttingPlane
360 const primitiveMesh& mesh,
361 const UList<label>& cellIdLabels
366 reCut(mesh, cellIdLabels);
371 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
373 // recut mesh with existing planeDesc
374 void Foam::cuttingPlane::reCut
376 const primitiveMesh& mesh,
377 const UList<label>& cellIdLabels
380 MeshStorage::clear();
383 scalarField dotProducts = (mesh.points() - refPoint()) & normal();
385 // Determine cells that are (probably) cut.
386 calcCutCells(mesh, dotProducts, cellIdLabels);
388 // Determine cutPoints and return list of edge cuts.
389 // per edge -1 or the label of the intersection point
391 intersectEdges(mesh, dotProducts, edgePoint);
393 // Do topological walk around cell to find closed loop.
394 walkCellCuts(mesh, edgePoint);
398 // remap action on triangulation
399 void Foam::cuttingPlane::remapFaces
401 const UList<label>& faceMap
404 // recalculate the cells cut
405 if (!faceMap.empty())
407 MeshStorage::remapFaces(faceMap);
409 List<label> newCutCells(faceMap.size());
410 forAll(faceMap, faceI)
412 newCutCells[faceI] = cutCells_[faceMap[faceI]];
414 cutCells_.transfer(newCutCells);
418 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
420 void Foam::cuttingPlane::operator=(const cuttingPlane& rhs)
422 // Check for assignment to self
425 FatalErrorIn ("Foam::cuttingPlane::operator=(const cuttingPlane&)")
426 << "Attempted assignment to self"
427 << abort(FatalError);
430 static_cast<MeshStorage&>(*this) = rhs;
431 static_cast<plane&>(*this) = rhs;
432 cutCells_ = rhs.cutCells();
436 // ************************************************************************* //