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

orientedSurface.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 Description
00025 
00026 \*---------------------------------------------------------------------------*/
00027 
00028 #include "orientedSurface.H"
00029 #include <meshTools/triSurfaceTools.H>
00030 #include <meshTools/treeBoundBox.H>
00031 
00032 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00033 
00034 defineTypeNameAndDebug(Foam::orientedSurface, 0);
00035 
00036 
00037 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00038 
00039 // Return true if face uses edge from start to end.
00040 bool Foam::orientedSurface::edgeOrder
00041 (
00042     const labelledTri& f,
00043     const edge& e
00044 )
00045 {
00046     if
00047     (
00048         (f[0] == e[0] && f[1] == e[1])
00049      || (f[1] == e[0] && f[2] == e[1])
00050      || (f[2] == e[0] && f[0] == e[1])
00051     )
00052     {
00053         return true;
00054     }
00055     else
00056     {
00057         return false;
00058     }
00059 }
00060 
00061 
00062 // Return true if edge is used in opposite order in faces
00063 bool Foam::orientedSurface::consistentEdge
00064 (
00065     const edge& e,
00066     const labelledTri& f0,
00067     const labelledTri& f1
00068 )
00069 {
00070     return edgeOrder(f0, e) ^ edgeOrder(f1, e);
00071 }
00072 
00073 
00074 Foam::labelList Foam::orientedSurface::faceToEdge
00075 (
00076     const triSurface& s,
00077     const labelList& changedFaces
00078 )
00079 {
00080     labelList changedEdges(3*changedFaces.size());
00081     label changedI = 0;
00082 
00083     forAll(changedFaces, i)
00084     {
00085         const labelList& fEdges = s.faceEdges()[changedFaces[i]];
00086 
00087         forAll(fEdges, j)
00088         {
00089             changedEdges[changedI++] = fEdges[j];
00090         }
00091     }
00092     changedEdges.setSize(changedI);
00093 
00094     return changedEdges;
00095 }
00096 
00097 
00098 Foam::labelList Foam::orientedSurface::edgeToFace
00099 (
00100     const triSurface& s,
00101     const labelList& changedEdges,
00102     labelList& flip
00103 )
00104 {
00105     labelList changedFaces(2*changedEdges.size());
00106     label changedI = 0;
00107 
00108     forAll(changedEdges, i)
00109     {
00110         label edgeI = changedEdges[i];
00111 
00112         const labelList& eFaces = s.edgeFaces()[edgeI];
00113 
00114         if (eFaces.size() < 2)
00115         {
00116             // Do nothing, faces was already visited.
00117         }
00118         else if (eFaces.size() == 2)
00119         {
00120             label face0 = eFaces[0];
00121             label face1 = eFaces[1];
00122 
00123             const labelledTri& f0 = s.localFaces()[face0];
00124             const labelledTri& f1 = s.localFaces()[face1];
00125 
00126             if (flip[face0] == UNVISITED)
00127             {
00128                 if (flip[face1] == UNVISITED)
00129                 {
00130                     FatalErrorIn("orientedSurface::edgeToFace") << "Problem"
00131                         << abort(FatalError);
00132                 }
00133                 else
00134                 {
00135                     // Face1 has a flip state, face0 hasn't
00136                     if (consistentEdge(s.edges()[edgeI], f0, f1))
00137                     {
00138                         // Take over flip status
00139                         flip[face0] = (flip[face1] == FLIP ? FLIP : NOFLIP);
00140                     }
00141                     else
00142                     {
00143                         // Invert
00144                         flip[face0] = (flip[face1] == FLIP ? NOFLIP : FLIP);
00145                     }
00146                     changedFaces[changedI++] = face0;
00147                 }
00148             }
00149             else
00150             {
00151                 if (flip[face1] == UNVISITED)
00152                 {
00153                     // Face0 has a flip state, face1 hasn't
00154                     if (consistentEdge(s.edges()[edgeI], f0, f1))
00155                     {
00156                         flip[face1] = (flip[face0] == FLIP ? FLIP : NOFLIP);
00157                     }
00158                     else
00159                     {
00160                         flip[face1] = (flip[face0] == FLIP ? NOFLIP : FLIP);
00161                     }
00162                     changedFaces[changedI++] = face1;
00163                 }
00164             }
00165         }
00166         else
00167         {
00168             // Multiply connected. Do what?
00169         }
00170     }
00171     changedFaces.setSize(changedI);
00172 
00173     return changedFaces;
00174 }
00175 
00176 
00177 void Foam::orientedSurface::walkSurface
00178 (
00179     const triSurface& s,
00180     const label startFaceI,
00181     labelList& flipState
00182 )
00183 {
00184     // List of faces that were changed in the last iteration.
00185     labelList changedFaces(1, startFaceI);
00186     // List of edges that were changed in the last iteration.
00187     labelList changedEdges;
00188 
00189     while(true)
00190     {
00191         changedEdges = faceToEdge(s, changedFaces);
00192 
00193         if (debug)
00194         {
00195             Pout<< "From changedFaces:" << changedFaces.size()
00196                 << " to changedEdges:" << changedEdges.size()
00197                 << endl;
00198         }
00199 
00200         if (changedEdges.empty())
00201         {
00202             break;
00203         }
00204 
00205         changedFaces = edgeToFace(s, changedEdges, flipState);
00206 
00207         if (debug)
00208         {
00209             Pout<< "From changedEdges:" << changedEdges.size()
00210                 << " to changedFaces:" << changedFaces.size()
00211                 << endl;
00212         }
00213 
00214         if (changedFaces.empty())
00215         {
00216             break;
00217         }
00218     }
00219 }
00220 
00221 
00222 void Foam::orientedSurface::propagateOrientation
00223 (
00224     const triSurface& s,
00225     const point& samplePoint,
00226     const bool orientOutside,
00227     const label nearestFaceI,
00228     const point& nearestPt,
00229     labelList& flipState
00230 )
00231 {
00232     //
00233     // Determine orientation to normal on nearest face
00234     //
00235     triSurfaceTools::sideType side = triSurfaceTools::surfaceSide
00236     (
00237         s,
00238         samplePoint,
00239         nearestFaceI,
00240         nearestPt,
00241         10*SMALL
00242     );
00243 
00244     if (side == triSurfaceTools::UNKNOWN)
00245     {
00246         // Non-closed surface. Do what? For now behave as if no flipping
00247         // nessecary
00248         flipState[nearestFaceI] = NOFLIP;
00249     }
00250     else if ((side == triSurfaceTools::OUTSIDE) == orientOutside)
00251     {
00252         // outside & orientOutside or inside & !orientOutside
00253         // Normals on surface pointing correctly. No need to flip normals
00254         flipState[nearestFaceI] = NOFLIP;
00255     }
00256     else
00257     {
00258         // Need to flip normals.
00259         flipState[nearestFaceI] = FLIP;
00260     }
00261 
00262     if (debug)
00263     {
00264         vector n = triSurfaceTools::surfaceNormal(s, nearestFaceI, nearestPt);
00265 
00266         Pout<< "orientedSurface::propagateOrientation : starting face"
00267             << " orientation:" << nl
00268             << "     for samplePoint:" << samplePoint << nl
00269             << "     starting from point:" << nearestPt << nl
00270             << "     on face:" << nearestFaceI << nl
00271             << "     with normal:" << n << nl
00272             << "     decided side:" << label(side)
00273             << endl;
00274     }
00275 
00276     // Walk the surface from nearestFaceI, changing the flipstate.
00277     walkSurface(s, nearestFaceI, flipState);
00278 }
00279 
00280 
00281 bool Foam::orientedSurface::flipSurface
00282 (
00283     triSurface& s,
00284     const labelList& flipState
00285 )
00286 {
00287     bool hasFlipped = false;
00288 
00289     // Flip tris in s
00290     forAll(flipState, faceI)
00291     {
00292         if (flipState[faceI] == UNVISITED)
00293         {
00294             FatalErrorIn
00295             (
00296                 "orientSurface(const point&, const label, const point&)"
00297             )   << "unvisited face " << faceI
00298                 << abort(FatalError);
00299         }
00300         else if (flipState[faceI] == FLIP)
00301         {
00302             labelledTri& tri = s[faceI];
00303 
00304             label tmp = tri[0];
00305 
00306             tri[0] = tri[1];
00307             tri[1] = tmp;
00308 
00309             hasFlipped = true;
00310         }
00311     }
00312     // Recalculate normals
00313     s.clearOut();
00314 
00315     return hasFlipped;
00316 }
00317 
00318 
00319 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00320 
00321 // Null constructor
00322 Foam::orientedSurface::orientedSurface()
00323 :
00324     triSurface()
00325 {}
00326 
00327 
00328 // Construct from surface and point which defines outside
00329 Foam::orientedSurface::orientedSurface
00330 (
00331     const triSurface& surf,
00332     const point& samplePoint,
00333     const bool orientOutside
00334 )
00335 :
00336     triSurface(surf)
00337 {
00338     orient(*this, samplePoint, orientOutside);
00339 }
00340 
00341 
00342 // Construct from surface. Calculate outside point.
00343 Foam::orientedSurface::orientedSurface
00344 (
00345     const triSurface& surf,
00346     const bool orientOutside
00347 )
00348 :
00349     triSurface(surf)
00350 {
00351     // BoundBox calculation without localPoints
00352     treeBoundBox bb(surf.points(), surf.meshPoints());
00353 
00354     point outsidePoint = bb.max() + bb.span();
00355 
00356     orient(*this, outsidePoint, orientOutside);
00357 }
00358 
00359 
00360 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00361 
00362 bool Foam::orientedSurface::orient
00363 (
00364     triSurface& s,
00365     const point& samplePoint,
00366     const bool orientOutside
00367 )
00368 {
00369     bool anyFlipped = false;
00370 
00371     // Do initial flipping to make triangles consistent. Otherwise if the
00372     // nearest is e.g. on an edge inbetween inconsistent triangles it might
00373     // make the wrong decision.
00374     if (s.size() > 0)
00375     {
00376         // Whether face has to be flipped.
00377         //      UNVISITED: unvisited
00378         //      NOFLIP: no need to flip
00379         //      FLIP: need to flip
00380         labelList flipState(s.size(), UNVISITED);
00381 
00382         flipState[0] = NOFLIP;
00383         walkSurface(s, 0, flipState);
00384 
00385         anyFlipped = flipSurface(s, flipState);
00386     }
00387 
00388 
00389     // Whether face has to be flipped.
00390     //      UNVISITED: unvisited
00391     //      NOFLIP: no need to flip
00392     //      FLIP: need to flip
00393     labelList flipState(s.size(), UNVISITED);
00394 
00395 
00396     while (true)
00397     {
00398         // Linear search for nearest unvisited point on surface.
00399 
00400         scalar minDist = GREAT;
00401         point minPoint;
00402         label minFaceI = -1;
00403 
00404         forAll(s, faceI)
00405         {
00406             if (flipState[faceI] == UNVISITED)
00407             {
00408                 const labelledTri& f = s[faceI];
00409 
00410                 pointHit curHit =
00411                     triPointRef
00412                     (
00413                         s.points()[f[0]],
00414                         s.points()[f[1]],
00415                         s.points()[f[2]]
00416                     ).nearestPoint(samplePoint);
00417 
00418                 if (curHit.distance() < minDist)
00419                 {
00420                     minDist = curHit.distance();
00421                     minPoint = curHit.rawPoint();
00422                     minFaceI = faceI;
00423                 }
00424             }
00425         }
00426 
00427         // Did we find anything?
00428         if (minFaceI == -1)
00429         {
00430             break;
00431         }
00432 
00433         // From this nearest face see if needs to be flipped and then
00434         // go outwards.
00435         propagateOrientation
00436         (
00437             s,
00438             samplePoint,
00439             orientOutside,
00440             minFaceI,
00441             minPoint,
00442             flipState
00443         );
00444     }
00445 
00446     // Now finally flip triangles according to flipState.
00447     bool geomFlipped = flipSurface(s, flipState);
00448 
00449     return anyFlipped || geomFlipped;
00450 }
00451 
00452 
00453 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines