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

faceCollapser.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 "faceCollapser.H"
00029 #include <OpenFOAM/polyMesh.H>
00030 #include "polyTopoChange.H"
00031 #include <dynamicMesh/polyModifyPoint.H>
00032 #include <dynamicMesh/polyModifyFace.H>
00033 #include <dynamicMesh/polyRemoveFace.H>
00034 #include <OpenFOAM/SortableList.H>
00035 #include <meshTools/meshTools.H>
00036 #include <OpenFOAM/OFstream.H>
00037 
00038 
00039 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00040 
00041 // Insert labelList into labelHashSet. Optional excluded element.
00042 void Foam::faceCollapser::insert
00043 (
00044     const labelList& elems,
00045     const label excludeElem,
00046     labelHashSet& set
00047 )
00048 {
00049     forAll(elems, i)
00050     {
00051         if (elems[i] != excludeElem)
00052         {
00053             set.insert(elems[i]);
00054         }
00055     }
00056 }
00057 
00058 
00059 // Find edge amongst candidate edges. FatalError if none.
00060 Foam::label Foam::faceCollapser::findEdge
00061 (
00062     const edgeList& edges,
00063     const labelList& edgeLabels,
00064     const label v0,
00065     const label v1
00066 )
00067 {
00068     forAll(edgeLabels, i)
00069     {
00070         label edgeI = edgeLabels[i];
00071 
00072         const edge& e = edges[edgeI];
00073 
00074         if
00075         (
00076             (e[0] == v0 && e[1] == v1)
00077          || (e[0] == v1 && e[1] == v0)
00078         )
00079         {
00080             return edgeI;
00081         }
00082     }
00083 
00084     FatalErrorIn("findEdge") << "Cannot find edge between vertices " << v0
00085         << " and " << v1 << " in edge labels " << edgeLabels
00086         << abort(FatalError);
00087 
00088     return -1;
00089 }
00090 
00091 
00092 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00093 
00094 // Replace vertices in face
00095 void Foam::faceCollapser::filterFace
00096 (
00097     const Map<labelList>& splitEdges,
00098     const label faceI,
00099     polyTopoChange& meshMod
00100 ) const
00101 {
00102     const face& f = mesh_.faces()[faceI];
00103     const labelList& fEdges = mesh_.faceEdges()[faceI];
00104 
00105     // Space for replaced vertices and split edges.
00106     DynamicList<label> newFace(10 * f.size());
00107 
00108     forAll(f, fp)
00109     {
00110         label v0 = f[fp];
00111 
00112         newFace.append(v0);
00113 
00114         // Look ahead one to get edge.
00115         label fp1 = f.fcIndex(fp);
00116 
00117         label v1 = f[fp1];
00118 
00119         // Get split on edge if any.
00120         label edgeI = findEdge(mesh_.edges(), fEdges, v0, v1);
00121 
00122         Map<labelList>::const_iterator edgeFnd =
00123             splitEdges.find(edgeI);
00124 
00125         if (edgeFnd != splitEdges.end())
00126         {
00127             // edgeI has been split (by introducing new vertices).
00128             // Insert new vertices in face in correct order
00129             // (splitEdges was constructed to be from edge.start() to end())
00130 
00131             const labelList& extraVerts = edgeFnd();
00132 
00133             if (v0 == mesh_.edges()[edgeI].start())
00134             {
00135                 forAll(extraVerts, i)
00136                 {
00137                     newFace.append(extraVerts[i]);
00138                 }
00139             }
00140             else
00141             {
00142                 forAllReverse(extraVerts, i)
00143                 {
00144                     newFace.append(extraVerts[i]);
00145                 }
00146             }
00147         }
00148     }
00149     face newF(newFace.shrink());
00150 
00151     //Pout<< "Modifying face:" << faceI << " from " << f << " to " << newFace
00152     //    << endl;
00153 
00154     if (newF != f)
00155     {
00156         label nei = -1;
00157 
00158         label patchI = -1;
00159 
00160         if (mesh_.isInternalFace(faceI))
00161         {
00162             nei = mesh_.faceNeighbour()[faceI];
00163         }
00164         else
00165         {
00166             patchI = mesh_.boundaryMesh().whichPatch(faceI);
00167         }
00168 
00169         // Get current zone info
00170         label zoneID = mesh_.faceZones().whichZone(faceI);
00171 
00172         bool zoneFlip = false;
00173 
00174         if (zoneID >= 0)
00175         {
00176             const faceZone& fZone = mesh_.faceZones()[zoneID];
00177 
00178             zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)];
00179         }
00180 
00181         meshMod.setAction
00182         (
00183             polyModifyFace
00184             (
00185                 newF,                       // modified face
00186                 faceI,                      // label of face being modified
00187                 mesh_.faceOwner()[faceI],   // owner
00188                 nei,                        // neighbour
00189                 false,                      // face flip
00190                 patchI,                     // patch for face
00191                 false,                      // remove from zone
00192                 zoneID,                     // zone for face
00193                 zoneFlip                    // face flip in zone
00194             )
00195         );
00196     }
00197 }
00198 
00199 
00200 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00201 
00202 // Construct from mesh
00203 Foam::faceCollapser::faceCollapser(const polyMesh& mesh)
00204 :
00205     mesh_(mesh)
00206 {}
00207 
00208 
00209 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00210 
00211 void Foam::faceCollapser::setRefinement
00212 (
00213     const labelList& faceLabels,
00214     const labelList& fpStart,
00215     const labelList& fpEnd,
00216     polyTopoChange& meshMod
00217 ) const
00218 {
00219     const pointField& points = mesh_.points();
00220     const edgeList& edges = mesh_.edges();
00221     const faceList& faces = mesh_.faces();
00222     const labelListList& edgeFaces = mesh_.edgeFaces();
00223 
00224 
00225     // From split edge to newly introduced point(s). Can be more than one per
00226     // edge!
00227     Map<labelList> splitEdges(faceLabels.size());
00228 
00229     // Mark faces in any way affect by modifying points/edges. Used later on
00230     // to prevent having to redo all faces.
00231     labelHashSet affectedFaces(4*faceLabels.size());
00232 
00233 
00234     //
00235     // Add/remove vertices and construct mapping
00236     //
00237 
00238     forAll(faceLabels, i)
00239     {
00240         const label faceI = faceLabels[i];
00241 
00242         const face& f = faces[faceI];
00243 
00244         const label fpA = fpStart[i];
00245         const label fpB = fpEnd[i];
00246 
00247         const point& pA = points[f[fpA]];
00248         const point& pB = points[f[fpB]];
00249 
00250         Pout<< "Face:" << f << " collapsed to fp:" << fpA << ' '  << fpB
00251             << " with points:" << pA << ' ' << pB
00252             << endl;
00253 
00254         // Create line from fpA to fpB
00255         linePointRef lineAB(pA, pB);
00256 
00257         // Get projections of all vertices onto line.
00258 
00259         // Distance(squared) to pA for every point on face.
00260         SortableList<scalar> dist(f.size());
00261 
00262         dist[fpA] = 0;
00263         dist[fpB] = magSqr(pB - pA);
00264 
00265         // Step from fpA to fpB
00266         // ~~~~~~~~~~~~~~~~~~~~
00267         // (by incrementing)
00268 
00269         label fpMin1 = fpA;
00270         label fp = f.fcIndex(fpMin1);
00271 
00272         while (fp != fpB)
00273         {
00274             // See where fp sorts. Make sure it is above fpMin1!
00275             pointHit near = lineAB.nearestDist(points[f[fp]]);
00276 
00277             scalar w = magSqr(near.rawPoint() - pA);
00278 
00279             if (w <= dist[fpMin1])
00280             {
00281                 // Offset.
00282                 w = dist[fpMin1] + 1E-6*(dist[fpB] - dist[fpA]);
00283 
00284                 point newPoint
00285                 (
00286                     pA + Foam::sqrt(w / (dist[fpB] - dist[fpA]))*(pB - pA)
00287                 );
00288 
00289                 Pout<< "Adapting position of vertex " << f[fp] << " on face "
00290                     << f << " from " << near.rawPoint() << " to " << newPoint
00291                     << endl;
00292 
00293                 near.setPoint(newPoint);
00294             }
00295 
00296             // Responsability of caller to make sure polyModifyPoint is only
00297             // called once per point. (so max only one collapse face per
00298             // edge)
00299             meshMod.setAction
00300             (
00301                 polyModifyPoint
00302                 (
00303                     f[fp],
00304                     near.rawPoint(),
00305                     false,
00306                     -1,
00307                     true
00308                 )
00309             );
00310 
00311             dist[fp] = w;
00312 
00313             // Step to next vertex.
00314             fpMin1 = fp;
00315             fp = f.fcIndex(fpMin1);
00316         }
00317 
00318         // Step from fpA to fpB
00319         // ~~~~~~~~~~~~~~~~~~~~
00320         // (by decrementing)
00321 
00322         fpMin1 = fpA;
00323         fp = f.rcIndex(fpMin1);
00324 
00325         while (fp != fpB)
00326         {
00327             // See where fp sorts. Make sure it is below fpMin1!
00328             pointHit near = lineAB.nearestDist(points[f[fp]]);
00329 
00330             scalar w = magSqr(near.rawPoint() - pA);
00331 
00332             if (w <= dist[fpMin1])
00333             {
00334                 // Offset.
00335                 w = dist[fpMin1] + 1E-6*(dist[fpB] - dist[fpA]);
00336 
00337                 point newPoint
00338                 (
00339                     pA + Foam::sqrt(w / (dist[fpB] - dist[fpA]))*(pB - pA)
00340                 );
00341 
00342                 Pout<< "Adapting position of vertex " << f[fp] << " on face "
00343                     << f << " from " << near.rawPoint() << " to " << newPoint
00344                     << endl;
00345 
00346                 near.setPoint(newPoint);
00347             }
00348 
00349             // Responsability of caller to make sure polyModifyPoint is only
00350             // called once per point. (so max only one collapse face per
00351             // edge)
00352             meshMod.setAction
00353             (
00354                 polyModifyPoint
00355                 (
00356                     f[fp],
00357                     near.rawPoint(),
00358                     false,
00359                     -1,
00360                     true
00361                 )
00362             );
00363 
00364             dist[fp] = w;
00365 
00366             // Step to previous vertex.
00367             fpMin1 = fp;
00368             fp = f.rcIndex(fpMin1);
00369         }
00370 
00371         dist.sort();
00372 
00373         // Check that fpB sorts latest.
00374         if (dist.indices()[dist.size()-1] != fpB)
00375         {
00376             OFstream str("conflictingFace.obj");
00377             meshTools::writeOBJ(str, faceList(1, f), points);
00378 
00379             FatalErrorIn("faceCollapser::setRefinement")
00380                 << "Trying to collapse face:" << faceI << " vertices:" << f
00381                 << " to edges between vertices " << f[fpA] << " and "
00382                 << f[fpB] << " but " << f[fpB] << " does not seem to be the"
00383                 << " vertex furthest away from " << f[fpA] << endl
00384                 << "Dumped conflicting face to obj file conflictingFace.obj"
00385                 << abort(FatalError);
00386         }
00387 
00388 
00389         // From fp to index in sort:
00390         Pout<< "Face:" << f << " fpA:" << fpA << " fpB:" << fpB << nl;
00391 
00392         labelList sortedFp(f.size());
00393         forAll(dist.indices(), i)
00394         {
00395             label fp = dist.indices()[i];
00396 
00397             Pout<< "   fp:" << fp << " distance:" << dist[i] << nl;
00398 
00399             sortedFp[fp] = i;
00400         }
00401 
00402         const labelList& fEdges = mesh_.faceEdges()[faceI];
00403 
00404         // Now look up all edges in the face and see if they get extra
00405         // vertices inserted and build an edge-to-intersected-points table.
00406 
00407         // Order of inserted points is in edge order (from e.start to
00408         // e.end)
00409 
00410         forAll(f, fp)
00411         {
00412             label fp1 = f.fcIndex(fp);
00413 
00414             // Get index in sorted list
00415             label sorted0 = sortedFp[fp];
00416             label sorted1 = sortedFp[fp1];
00417 
00418             // Get indices in increasing order
00419             DynamicList<label> edgePoints(f.size());
00420 
00421             // Whether edgePoints are from fp to fp1
00422             bool fpToFp1;
00423 
00424             if (sorted0 < sorted1)
00425             {
00426                 fpToFp1 = true;
00427 
00428                 for (label j = sorted0+1; j < sorted1; j++)
00429                 {
00430                     edgePoints.append(f[dist.indices()[j]]);
00431                 }
00432             }
00433             else
00434             {
00435                 fpToFp1 = false;
00436 
00437                 for (label j = sorted1+1; j < sorted0; j++)
00438                 {
00439                     edgePoints.append(f[dist.indices()[j]]);
00440                 }
00441             }
00442 
00443             if (edgePoints.size())
00444             {
00445                 edgePoints.shrink();
00446 
00447                 label edgeI = findEdge(edges, fEdges, f[fp], f[fp1]);
00448 
00449                 const edge& e = edges[edgeI];
00450 
00451                 if (fpToFp1 == (f[fp] == e.start()))
00452                 {
00453                     splitEdges.insert(edgeI, edgePoints);
00454                 }
00455                 else
00456                 {
00457                     reverse(edgePoints);
00458                     splitEdges.insert(edgeI, edgePoints);
00459                 }
00460 
00461                 // Mark all faces affected
00462                 insert(edgeFaces[edgeI], faceI, affectedFaces);
00463             }
00464         }
00465     }
00466 
00467     for
00468     (
00469         Map<labelList>::const_iterator iter = splitEdges.begin();
00470         iter != splitEdges.end();
00471         ++iter
00472     )
00473     {
00474         Pout<< "Split edge:" << iter.key()
00475             << " verts:" << mesh_.edges()[iter.key()]
00476             << " in:" << nl;
00477         const labelList& edgePoints = iter();
00478 
00479         forAll(edgePoints, i)
00480         {
00481             Pout<< "    " << edgePoints[i] << nl;
00482         }
00483     }
00484 
00485 
00486     //
00487     // Remove faces.
00488     //
00489 
00490     forAll(faceLabels, i)
00491     {
00492         const label faceI = faceLabels[i];
00493 
00494         meshMod.setAction(polyRemoveFace(faceI));
00495 
00496         // Update list of faces we still have to modify
00497         affectedFaces.erase(faceI);
00498     }
00499 
00500 
00501     //
00502     // Modify faces affected (but not removed)
00503     //
00504 
00505     for
00506     (
00507         labelHashSet::const_iterator iter = affectedFaces.begin();
00508         iter != affectedFaces.end();
00509         ++iter
00510     )
00511     {
00512         filterFace(splitEdges, iter.key(), meshMod);
00513     }
00514 }
00515 
00516 
00517 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines