1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 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
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;
38 //! @endcond localScope
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 void Foam::cuttingPlane::calcCutCells
45 const primitiveMesh& mesh,
46 const scalarField& dotProducts,
47 const UList<label>& 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 UList<label>& 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 UList<label>& edgePoint
263 const pointField& cutPoints = this->points();
265 // use dynamic lists to handle triangulation and/or missed cuts
266 DynamicList<face> dynCutFaces(cutCells_.size());
267 DynamicList<label> dynCutCells(cutCells_.size());
269 // scratch space for calculating the face vertices
270 DynamicList<label> faceVerts(10);
274 label cellI = cutCells_[i];
276 // Find the starting edge to walk from.
277 const labelList& cEdges = mesh.cellEdges()[cellI];
279 label startEdgeI = -1;
281 forAll(cEdges, cEdgeI)
283 label edgeI = cEdges[cEdgeI];
285 if (edgePoint[edgeI] != -1)
292 // Check for the unexpected ...
293 if (startEdgeI == -1)
295 FatalErrorIn("Foam::cuttingPlane::walkCellCuts")
296 << "Cannot find cut edge for cut cell " << cellI
297 << abort(FatalError);
300 // Walk from starting edge around the circumference of the cell.
301 bool okCut = walkCell
314 // Orient face to point in the same direction as the plane normal
315 if ((f.normal(cutPoints) & normal()) < 0)
320 // the cut faces are usually quite ugly, so always triangulate
321 label nTri = f.triangles(cutPoints, dynCutFaces);
324 dynCutCells.append(cellI);
329 this->storedFaces().transfer(dynCutFaces);
330 cutCells_.transfer(dynCutCells);
334 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
336 // Construct without cutting
337 Foam::cuttingPlane::cuttingPlane(const plane& pln)
343 // Construct from plane and mesh reference, restricted to a list of cells
344 Foam::cuttingPlane::cuttingPlane
347 const primitiveMesh& mesh,
348 const UList<label>& cellIdLabels
353 reCut(mesh, cellIdLabels);
358 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
360 // recut mesh with existing planeDesc
361 void Foam::cuttingPlane::reCut
363 const primitiveMesh& mesh,
364 const UList<label>& cellIdLabels
367 MeshStorage::clear();
370 scalarField dotProducts = (mesh.points() - refPoint()) & normal();
372 // Determine cells that are (probably) cut.
373 calcCutCells(mesh, dotProducts, cellIdLabels);
375 // Determine cutPoints and return list of edge cuts.
376 // per edge -1 or the label of the intersection point
378 intersectEdges(mesh, dotProducts, edgePoint);
380 // Do topological walk around cell to find closed loop.
381 walkCellCuts(mesh, edgePoint);
385 // remap action on triangulation
386 void Foam::cuttingPlane::remapFaces
388 const UList<label>& faceMap
391 // recalculate the cells cut
392 if (&faceMap && faceMap.size())
394 MeshStorage::remapFaces(faceMap);
396 List<label> newCutCells(faceMap.size());
397 forAll(faceMap, faceI)
399 newCutCells[faceI] = cutCells_[faceMap[faceI]];
401 cutCells_.transfer(newCutCells);
405 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
407 void Foam::cuttingPlane::operator=(const cuttingPlane& rhs)
409 // Check for assignment to self
412 FatalErrorIn ("Foam::cuttingPlane::operator=(const cuttingPlane&)")
413 << "Attempted assignment to self"
414 << abort(FatalError);
417 static_cast<MeshStorage&>(*this) = rhs;
418 static_cast<plane&>(*this) = rhs;
419 cutCells_ = rhs.cutCells();
423 // ************************************************************************* //