1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "cuttingPlane.H"
27 #include "primitiveMesh.H"
28 #include "linePointRef.H"
29 #include "meshTools.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 // set values for what is close to zero and what is considered to
34 // be positive (and not just rounding noise)
36 const Foam::scalar zeroish = Foam::SMALL;
37 const Foam::scalar positive = Foam::SMALL * 1E3;
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 void Foam::cuttingPlane::calcCutCells
45 const primitiveMesh& mesh,
46 const scalarField& dotProducts,
47 const labelUList& cellIdLabels
50 const labelListList& cellEdges = mesh.cellEdges();
51 const edgeList& edges = mesh.edges();
53 label listSize = cellEdges.size();
56 listSize = cellIdLabels.size();
59 cutCells_.setSize(listSize);
62 // Find the cut cells by detecting any cell that uses points with
63 // opposing dotProducts.
64 for (label listI = 0; listI < listSize; ++listI)
69 cellI = cellIdLabels[listI];
72 const labelList& cEdges = cellEdges[cellI];
78 const edge& e = edges[cEdges[i]];
82 (dotProducts[e[0]] < zeroish && dotProducts[e[1]] > positive)
83 || (dotProducts[e[1]] < zeroish && dotProducts[e[0]] > positive)
90 cutCells_[cutcellI++] = cellI;
98 // Set correct list size
99 cutCells_.setSize(cutcellI);
103 // Determine for each edge the intersection point. Calculates
104 // - cutPoints_ : coordinates of all intersection points
105 // - edgePoint : per edge -1 or the index into cutPoints
106 void Foam::cuttingPlane::intersectEdges
108 const primitiveMesh& mesh,
109 const scalarField& dotProducts,
110 List<label>& edgePoint
113 // Use the dotProducts to find out the cut edges.
114 const edgeList& edges = mesh.edges();
115 const pointField& points = mesh.points();
117 // Per edge -1 or the label of the intersection point
118 edgePoint.setSize(edges.size());
120 DynamicList<point> dynCuttingPoints(4*cutCells_.size());
124 const edge& e = edges[edgeI];
128 (dotProducts[e[0]] < zeroish && dotProducts[e[1]] > positive)
129 || (dotProducts[e[1]] < zeroish && dotProducts[e[0]] > positive)
133 edgePoint[edgeI] = dynCuttingPoints.size();
135 const point& p0 = points[e[0]];
136 const point& p1 = points[e[1]];
138 scalar alpha = lineIntersect(linePointRef(p0, p1));
142 dynCuttingPoints.append(p0);
144 else if (alpha >= 1.0)
146 dynCuttingPoints.append(p1);
150 dynCuttingPoints.append((1-alpha)*p0 + alpha*p1);
155 edgePoint[edgeI] = -1;
159 this->storedPoints().transfer(dynCuttingPoints);
163 // Coming from startEdgeI cross the edge to the other face
164 // across to the next cut edge.
165 bool Foam::cuttingPlane::walkCell
167 const primitiveMesh& mesh,
168 const labelUList& edgePoint,
170 const label startEdgeI,
171 DynamicList<label>& faceVerts
175 label edgeI = startEdgeI;
182 faceVerts.append(edgePoint[edgeI]);
184 // Cross edge to other face
185 faceI = meshTools::otherFace(mesh, cellI, faceI, edgeI);
187 // Find next cut edge on face.
188 const labelList& fEdges = mesh.faceEdges()[faceI];
190 label nextEdgeI = -1;
192 //Note: here is where we should check for whether there are more
193 // than 2 intersections with the face (warped/non-convex face).
194 // If so should e.g. decompose the cells on both faces and redo
199 label edge2I = fEdges[i];
201 if (edge2I != edgeI && edgePoint[edge2I] != -1)
210 // Did not find another cut edge on faceI. Do what?
211 WarningIn("Foam::cuttingPlane::walkCell")
212 << "Did not find closed walk along surface of cell " << cellI
213 << " starting from edge " << startEdgeI
214 << " in " << nIter << " iterations." << nl
215 << "Collected cutPoints so far:" << faceVerts
227 WarningIn("Foam::cuttingPlane::walkCell")
228 << "Did not find closed walk along surface of cell " << cellI
229 << " starting from edge " << startEdgeI
230 << " in " << nIter << " iterations." << nl
231 << "Collected cutPoints so far:" << faceVerts
236 } while (edgeI != startEdgeI);
239 if (faceVerts.size() >= 3)
245 WarningIn("Foam::cuttingPlane::walkCell")
246 << "Did not find closed walk along surface of cell " << cellI
247 << " starting from edge " << startEdgeI << nl
248 << "Collected cutPoints so far:" << faceVerts
256 // For every cut cell determine a walk through all? its cuts.
257 void Foam::cuttingPlane::walkCellCuts
259 const primitiveMesh& mesh,
260 const bool triangulate,
261 const labelUList& edgePoint
264 const pointField& cutPoints = this->points();
266 // use dynamic lists to handle triangulation and/or missed cuts
267 DynamicList<face> dynCutFaces(cutCells_.size());
268 DynamicList<label> dynCutCells(cutCells_.size());
270 // scratch space for calculating the face vertices
271 DynamicList<label> faceVerts(10);
275 label cellI = cutCells_[i];
277 // Find the starting edge to walk from.
278 const labelList& cEdges = mesh.cellEdges()[cellI];
280 label startEdgeI = -1;
282 forAll(cEdges, cEdgeI)
284 label edgeI = cEdges[cEdgeI];
286 if (edgePoint[edgeI] != -1)
293 // Check for the unexpected ...
294 if (startEdgeI == -1)
296 FatalErrorIn("Foam::cuttingPlane::walkCellCuts(..)")
297 << "Cannot find cut edge for cut cell " << cellI
298 << abort(FatalError);
301 // Walk from starting edge around the circumference of the cell.
302 bool okCut = walkCell
315 // Orient face to point in the same direction as the plane normal
316 if ((f.normal(cutPoints) & normal()) < 0)
321 // the cut faces are usually quite ugly, so optionally triangulate
324 label nTri = f.triangles(cutPoints, dynCutFaces);
327 dynCutCells.append(cellI);
332 dynCutFaces.append(f);
333 dynCutCells.append(cellI);
338 this->storedFaces().transfer(dynCutFaces);
339 cutCells_.transfer(dynCutCells);
343 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
345 // Construct without cutting
346 Foam::cuttingPlane::cuttingPlane(const plane& pln)
352 // Construct from plane and mesh reference, restricted to a list of cells
353 Foam::cuttingPlane::cuttingPlane
356 const primitiveMesh& mesh,
357 const bool triangulate,
358 const labelUList& cellIdLabels
363 reCut(mesh, triangulate, cellIdLabels);
368 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
370 // recut mesh with existing planeDesc
371 void Foam::cuttingPlane::reCut
373 const primitiveMesh& mesh,
374 const bool triangulate,
375 const labelUList& cellIdLabels
378 MeshStorage::clear();
381 const scalarField dotProducts((mesh.points() - refPoint()) & normal());
383 // Determine cells that are (probably) cut.
384 calcCutCells(mesh, dotProducts, cellIdLabels);
386 // Determine cutPoints and return list of edge cuts.
387 // per edge -1 or the label of the intersection point
389 intersectEdges(mesh, dotProducts, edgePoint);
391 // Do topological walk around cell to find closed loop.
392 walkCellCuts(mesh, triangulate, edgePoint);
396 // remap action on triangulation
397 void Foam::cuttingPlane::remapFaces
399 const labelUList& faceMap
402 // recalculate the cells cut
403 if (&faceMap && faceMap.size())
405 MeshStorage::remapFaces(faceMap);
407 List<label> newCutCells(faceMap.size());
408 forAll(faceMap, faceI)
410 newCutCells[faceI] = cutCells_[faceMap[faceI]];
412 cutCells_.transfer(newCutCells);
416 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
418 void Foam::cuttingPlane::operator=(const cuttingPlane& rhs)
420 // Check for assignment to self
423 FatalErrorIn ("Foam::cuttingPlane::operator=(const cuttingPlane&)")
424 << "Attempted assignment to self"
425 << abort(FatalError);
428 static_cast<MeshStorage&>(*this) = rhs;
429 static_cast<plane&>(*this) = rhs;
430 cutCells_ = rhs.cutCells();
434 // ************************************************************************* //