FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

cuttingPlane.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*---------------------------------------------------------------------------*/
00025 
00026 #include "cuttingPlane.H"
00027 #include <OpenFOAM/primitiveMesh.H>
00028 #include <OpenFOAM/linePointRef.H>
00029 #include <meshTools/meshTools.H>
00030 
00031 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00032 
00033 // set values for what is close to zero and what is considered to
00034 // be positive (and not just rounding noise)
00036 const Foam::scalar zeroish  = Foam::SMALL;
00037 const Foam::scalar positive = Foam::SMALL * 1E3;
00039 
00040 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00041 
00042 // Find cut cells
00043 void Foam::cuttingPlane::calcCutCells
00044 (
00045     const primitiveMesh& mesh,
00046     const scalarField& dotProducts,
00047     const UList<label>& cellIdLabels
00048 )
00049 {
00050     const labelListList& cellEdges = mesh.cellEdges();
00051     const edgeList& edges = mesh.edges();
00052 
00053     label listSize = cellEdges.size();
00054     if (&cellIdLabels)
00055     {
00056         listSize = cellIdLabels.size();
00057     }
00058 
00059     cutCells_.setSize(listSize);
00060     label cutcellI(0);
00061 
00062     // Find the cut cells by detecting any cell that uses points with
00063     // opposing dotProducts.
00064     for (label listI = 0; listI < listSize; ++listI)
00065     {
00066         label cellI = listI;
00067         if (&cellIdLabels)
00068         {
00069             cellI = cellIdLabels[listI];
00070         }
00071 
00072         const labelList& cEdges = cellEdges[cellI];
00073 
00074         label nCutEdges = 0;
00075 
00076         forAll(cEdges, i)
00077         {
00078             const edge& e = edges[cEdges[i]];
00079 
00080             if
00081             (
00082                 (dotProducts[e[0]] < zeroish && dotProducts[e[1]] > positive)
00083              || (dotProducts[e[1]] < zeroish && dotProducts[e[0]] > positive)
00084             )
00085             {
00086                 nCutEdges++;
00087 
00088                 if (nCutEdges > 2)
00089                 {
00090                     cutCells_[cutcellI++] = cellI;
00091 
00092                     break;
00093                 }
00094             }
00095         }
00096     }
00097 
00098     // Set correct list size
00099     cutCells_.setSize(cutcellI);
00100 }
00101 
00102 
00103 // Determine for each edge the intersection point. Calculates
00104 // - cutPoints_ : coordinates of all intersection points
00105 // - edgePoint  : per edge -1 or the index into cutPoints
00106 void Foam::cuttingPlane::intersectEdges
00107 (
00108     const primitiveMesh& mesh,
00109     const scalarField& dotProducts,
00110     List<label>& edgePoint
00111 )
00112 {
00113     // Use the dotProducts to find out the cut edges.
00114     const edgeList& edges = mesh.edges();
00115     const pointField& points = mesh.points();
00116 
00117     // Per edge -1 or the label of the intersection point
00118     edgePoint.setSize(edges.size());
00119 
00120     DynamicList<point> dynCuttingPoints(4*cutCells_.size());
00121 
00122     forAll(edges, edgeI)
00123     {
00124         const edge& e = edges[edgeI];
00125 
00126         if
00127         (
00128             (dotProducts[e[0]] < zeroish && dotProducts[e[1]] > positive)
00129          || (dotProducts[e[1]] < zeroish && dotProducts[e[0]] > positive)
00130         )
00131         {
00132             // Edge is cut
00133             edgePoint[edgeI] = dynCuttingPoints.size();
00134 
00135             const point& p0 = points[e[0]];
00136             const point& p1 = points[e[1]];
00137 
00138             scalar alpha = lineIntersect(linePointRef(p0, p1));
00139 
00140             if (alpha < zeroish)
00141             {
00142                 dynCuttingPoints.append(p0);
00143             }
00144             else if (alpha >= 1.0)
00145             {
00146                 dynCuttingPoints.append(p1);
00147             }
00148             else
00149             {
00150                 dynCuttingPoints.append((1-alpha)*p0 + alpha*p1);
00151             }
00152         }
00153         else
00154         {
00155             edgePoint[edgeI] = -1;
00156         }
00157     }
00158 
00159     this->storedPoints().transfer(dynCuttingPoints);
00160 }
00161 
00162 
00163 // Coming from startEdgeI cross the edge to the other face
00164 // across to the next cut edge.
00165 bool Foam::cuttingPlane::walkCell
00166 (
00167     const primitiveMesh& mesh,
00168     const UList<label>& edgePoint,
00169     const label cellI,
00170     const label startEdgeI,
00171     DynamicList<label>& faceVerts
00172 )
00173 {
00174     label faceI = -1;
00175     label edgeI = startEdgeI;
00176 
00177     label nIter = 0;
00178 
00179     faceVerts.clear();
00180     do
00181     {
00182         faceVerts.append(edgePoint[edgeI]);
00183 
00184         // Cross edge to other face
00185         faceI = meshTools::otherFace(mesh, cellI, faceI, edgeI);
00186 
00187         // Find next cut edge on face.
00188         const labelList& fEdges = mesh.faceEdges()[faceI];
00189 
00190         label nextEdgeI = -1;
00191 
00192         //Note: here is where we should check for whether there are more
00193         // than 2 intersections with the face (warped/non-convex face).
00194         // If so should e.g. decompose the cells on both faces and redo
00195         // the calculation.
00196 
00197         forAll(fEdges, i)
00198         {
00199             label edge2I = fEdges[i];
00200 
00201             if (edge2I != edgeI && edgePoint[edge2I] != -1)
00202             {
00203                 nextEdgeI = edge2I;
00204                 break;
00205             }
00206         }
00207 
00208         if (nextEdgeI == -1)
00209         {
00210             // Did not find another cut edge on faceI. Do what?
00211             WarningIn("Foam::cuttingPlane::walkCell")
00212                 << "Did not find closed walk along surface of cell " << cellI
00213                 << " starting from edge " << startEdgeI
00214                 << " in " << nIter << " iterations." << nl
00215                 << "Collected cutPoints so far:" << faceVerts
00216                 << endl;
00217 
00218             return false;
00219         }
00220 
00221         edgeI = nextEdgeI;
00222 
00223         nIter++;
00224 
00225         if (nIter > 1000)
00226         {
00227             WarningIn("Foam::cuttingPlane::walkCell")
00228                 << "Did not find closed walk along surface of cell " << cellI
00229                 << " starting from edge " << startEdgeI
00230                 << " in " << nIter << " iterations." << nl
00231                 << "Collected cutPoints so far:" << faceVerts
00232                 << endl;
00233             return false;
00234         }
00235 
00236     } while (edgeI != startEdgeI);
00237 
00238 
00239     if (faceVerts.size() >= 3)
00240     {
00241         return true;
00242     }
00243     else
00244     {
00245         WarningIn("Foam::cuttingPlane::walkCell")
00246             << "Did not find closed walk along surface of cell " << cellI
00247             << " starting from edge " << startEdgeI << nl
00248             << "Collected cutPoints so far:" << faceVerts
00249             << endl;
00250 
00251         return false;
00252     }
00253 }
00254 
00255 
00256 // For every cut cell determine a walk through all? its cuts.
00257 void Foam::cuttingPlane::walkCellCuts
00258 (
00259     const primitiveMesh& mesh,
00260     const UList<label>& edgePoint
00261 )
00262 {
00263     const pointField& cutPoints = this->points();
00264 
00265     // use dynamic lists to handle triangulation and/or missed cuts
00266     DynamicList<face>  dynCutFaces(cutCells_.size());
00267     DynamicList<label> dynCutCells(cutCells_.size());
00268 
00269     // scratch space for calculating the face vertices
00270     DynamicList<label> faceVerts(10);
00271 
00272     forAll(cutCells_, i)
00273     {
00274         label cellI = cutCells_[i];
00275 
00276         // Find the starting edge to walk from.
00277         const labelList& cEdges = mesh.cellEdges()[cellI];
00278 
00279         label startEdgeI = -1;
00280 
00281         forAll(cEdges, cEdgeI)
00282         {
00283             label edgeI = cEdges[cEdgeI];
00284 
00285             if (edgePoint[edgeI] != -1)
00286             {
00287                 startEdgeI = edgeI;
00288                 break;
00289             }
00290         }
00291 
00292         // Check for the unexpected ...
00293         if (startEdgeI == -1)
00294         {
00295             FatalErrorIn("Foam::cuttingPlane::walkCellCuts")
00296                 << "Cannot find cut edge for cut cell " << cellI
00297                 << abort(FatalError);
00298         }
00299 
00300         // Walk from starting edge around the circumference of the cell.
00301         bool okCut = walkCell
00302         (
00303             mesh,
00304             edgePoint,
00305             cellI,
00306             startEdgeI,
00307             faceVerts
00308         );
00309 
00310         if (okCut)
00311         {
00312             face f(faceVerts);
00313 
00314             // Orient face to point in the same direction as the plane normal
00315             if ((f.normal(cutPoints) & normal()) < 0)
00316             {
00317                 f = f.reverseFace();
00318             }
00319 
00320             // the cut faces are usually quite ugly, so always triangulate
00321             label nTri = f.triangles(cutPoints, dynCutFaces);
00322             while (nTri--)
00323             {
00324                 dynCutCells.append(cellI);
00325             }
00326         }
00327     }
00328 
00329     this->storedFaces().transfer(dynCutFaces);
00330     cutCells_.transfer(dynCutCells);
00331 }
00332 
00333 
00334 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00335 
00336 // Construct without cutting
00337 Foam::cuttingPlane::cuttingPlane(const plane& pln)
00338 :
00339     plane(pln)
00340 {}
00341 
00342 
00343 // Construct from plane and mesh reference, restricted to a list of cells
00344 Foam::cuttingPlane::cuttingPlane
00345 (
00346     const plane& pln,
00347     const primitiveMesh& mesh,
00348     const UList<label>& cellIdLabels
00349 )
00350 :
00351     plane(pln)
00352 {
00353     reCut(mesh, cellIdLabels);
00354 }
00355 
00356 
00357 
00358 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00359 
00360 // recut mesh with existing planeDesc
00361 void Foam::cuttingPlane::reCut
00362 (
00363     const primitiveMesh& mesh,
00364     const UList<label>& cellIdLabels
00365 )
00366 {
00367     MeshStorage::clear();
00368     cutCells_.clear();
00369 
00370     scalarField dotProducts = (mesh.points() - refPoint()) & normal();
00371 
00372     // Determine cells that are (probably) cut.
00373     calcCutCells(mesh, dotProducts, cellIdLabels);
00374 
00375     // Determine cutPoints and return list of edge cuts.
00376     // per edge -1 or the label of the intersection point
00377     labelList edgePoint;
00378     intersectEdges(mesh, dotProducts, edgePoint);
00379 
00380     // Do topological walk around cell to find closed loop.
00381     walkCellCuts(mesh, edgePoint);
00382 }
00383 
00384 
00385 // remap action on triangulation
00386 void Foam::cuttingPlane::remapFaces
00387 (
00388     const UList<label>& faceMap
00389 )
00390 {
00391     // recalculate the cells cut
00392     if (&faceMap && faceMap.size())
00393     {
00394         MeshStorage::remapFaces(faceMap);
00395 
00396         List<label> newCutCells(faceMap.size());
00397         forAll(faceMap, faceI)
00398         {
00399             newCutCells[faceI] = cutCells_[faceMap[faceI]];
00400         }
00401         cutCells_.transfer(newCutCells);
00402     }
00403 }
00404 
00405 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
00406 
00407 void Foam::cuttingPlane::operator=(const cuttingPlane& rhs)
00408 {
00409     // Check for assignment to self
00410     if (this == &rhs)
00411     {
00412         FatalErrorIn ("Foam::cuttingPlane::operator=(const cuttingPlane&)")
00413             << "Attempted assignment to self"
00414             << abort(FatalError);
00415     }
00416 
00417     static_cast<MeshStorage&>(*this) = rhs;
00418     static_cast<plane&>(*this) = rhs;
00419     cutCells_ = rhs.cutCells();
00420 }
00421 
00422 
00423 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines