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

face.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 "face.H"
00027 #include <OpenFOAM/triFace.H>
00028 #include <OpenFOAM/triPointRef.H>
00029 #include <OpenFOAM/mathematicalConstants.H>
00030 
00031 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00032 
00033 const char* const Foam::face::typeName = "face";
00034 
00035 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00036 
00037 Foam::tmp<Foam::vectorField>
00038 Foam::face::calcEdges(const pointField& points) const
00039 {
00040     tmp<vectorField> tedges(new vectorField(size()));
00041     vectorField& edges = tedges();
00042 
00043     forAll(*this, i)
00044     {
00045         label ni = fcIndex(i);
00046 
00047         point thisPt = points[operator[](i)];
00048         point nextPt = points[operator[](ni)];
00049 
00050         vector vec(nextPt - thisPt);
00051         vec /= Foam::mag(vec) + VSMALL;
00052 
00053         edges[i] = vec;
00054     }
00055 
00056     return tedges;
00057 }
00058 
00059 
00060 Foam::scalar Foam::face::edgeCos
00061 (
00062     const vectorField& edges,
00063     const label index
00064 ) const
00065 {
00066     label leftEdgeI = left(index);
00067     label rightEdgeI = right(index);
00068 
00069     // note negate on left edge to get correct left-pointing edge.
00070     return -(edges[leftEdgeI] & edges[rightEdgeI]);
00071 }
00072 
00073 
00074 Foam::label Foam::face::mostConcaveAngle
00075 (
00076     const pointField& points,
00077     const vectorField& edges,
00078     scalar& maxAngle
00079 ) const
00080 {
00081     vector n(normal(points));
00082 
00083     label index = 0;
00084     maxAngle = -GREAT;
00085 
00086     forAll(edges, i)
00087     {
00088         label leftEdgeI = left(i);
00089         label rightEdgeI = right(i);
00090 
00091         vector edgeNormal = edges[rightEdgeI] ^ edges[leftEdgeI];
00092 
00093         scalar edgeCos = edges[leftEdgeI] & edges[rightEdgeI];
00094         scalar edgeAngle = acos(max(-1.0, min(1.0, edgeCos)));
00095 
00096         scalar angle;
00097 
00098         if ((edgeNormal & n) > 0)
00099         {
00100             // Concave angle.
00101             angle = mathematicalConstant::pi + edgeAngle;
00102         }
00103         else
00104         {
00105             // Convex angle. Note '-' to take into account that rightEdge
00106             // and leftEdge are head-to-tail connected.
00107             angle = mathematicalConstant::pi - edgeAngle;
00108         }
00109 
00110         if (angle > maxAngle)
00111         {
00112             maxAngle = angle;
00113             index = i;
00114         }
00115     }
00116 
00117     return index;
00118 }
00119 
00120 
00121 Foam::label Foam::face::split
00122 (
00123     const face::splitMode mode,
00124     const pointField& points,
00125     label& triI,
00126     label& quadI,
00127     faceList& triFaces,
00128     faceList& quadFaces
00129 ) const
00130 {
00131     label oldIndices = (triI + quadI);
00132 
00133     if (size() <= 2)
00134     {
00135         FatalErrorIn
00136         (
00137             "face::split"
00138             "(const face::splitMode, const pointField&, label&, label&"
00139             ", faceList&, faceList&)"
00140         )
00141             << "Serious problem: asked to split a face with < 3 vertices"
00142             << abort(FatalError);
00143     }
00144     if (size() == 3)
00145     {
00146         // Triangle. Just copy.
00147         if (mode == COUNTTRIANGLE || mode == COUNTQUAD)
00148         {
00149             triI++;
00150         }
00151         else
00152         {
00153             triFaces[triI++] = *this;
00154         }
00155     }
00156     else if (size() == 4)
00157     {
00158         if (mode == COUNTTRIANGLE)
00159         {
00160             triI += 2;
00161         }
00162         if (mode == COUNTQUAD)
00163         {
00164             quadI++;
00165         }
00166         else if (mode == SPLITTRIANGLE)
00167         {
00168             //  Start at point with largest internal angle.
00169             const vectorField edges(calcEdges(points));
00170 
00171             scalar minAngle;
00172             label startIndex = mostConcaveAngle(points, edges, minAngle);
00173 
00174             label nextIndex = fcIndex(startIndex);
00175             label splitIndex = fcIndex(nextIndex);
00176 
00177             // Create triangles
00178             face triFace(3);
00179             triFace[0] = operator[](startIndex);
00180             triFace[1] = operator[](nextIndex);
00181             triFace[2] = operator[](splitIndex);
00182 
00183             triFaces[triI++] = triFace;
00184 
00185             triFace[0] = operator[](splitIndex);
00186             triFace[1] = operator[](fcIndex(splitIndex));
00187             triFace[2] = operator[](startIndex);
00188 
00189             triFaces[triI++] = triFace;
00190         }
00191         else
00192         {
00193             quadFaces[quadI++] = *this;
00194         }
00195     }
00196     else
00197     {
00198         // General case. Like quad: search for largest internal angle.
00199 
00200         const vectorField edges(calcEdges(points));
00201 
00202         scalar minAngle = 1;
00203         label startIndex = mostConcaveAngle(points, edges, minAngle);
00204 
00205         scalar bisectAngle = minAngle/2;
00206         vector rightEdge = edges[right(startIndex)];
00207 
00208         //
00209         // Look for opposite point which as close as possible bisects angle
00210         //
00211 
00212         // split candidate starts two points away.
00213         label index = fcIndex(fcIndex(startIndex));
00214 
00215         label minIndex = index;
00216         scalar minDiff = Foam::mathematicalConstant::pi;
00217 
00218         for(label i = 0; i < size() - 3; i++)
00219         {
00220             vector splitEdge
00221             (
00222                 points[operator[](index)]
00223               - points[operator[](startIndex)]
00224             );
00225             splitEdge /= Foam::mag(splitEdge) + VSMALL;
00226 
00227             const scalar splitCos = splitEdge & rightEdge;
00228             const scalar splitAngle = acos(max(-1.0, min(1.0, splitCos)));
00229             const scalar angleDiff = fabs(splitAngle - bisectAngle);
00230 
00231             if (angleDiff < minDiff)
00232             {
00233                 minDiff = angleDiff;
00234                 minIndex = index;
00235             }
00236 
00237             // go to next candidate
00238             index = fcIndex(index);
00239         }
00240 
00241 
00242         // Split into two subshapes.
00243         //     face1: startIndex to minIndex
00244         //     face2: minIndex to startIndex
00245 
00246         // Get sizes of the two subshapes
00247         label diff = 0;
00248         if (minIndex > startIndex)
00249         {
00250             diff = minIndex - startIndex;
00251         }
00252         else
00253         {
00254             // folded around
00255             diff = minIndex + size() - startIndex;
00256         }
00257 
00258         label nPoints1 = diff + 1;
00259         label nPoints2 = size() - diff + 1;
00260 
00261         // Collect face1 points
00262         face face1(nPoints1);
00263 
00264         index = startIndex;
00265         for (label i = 0; i < nPoints1; i++)
00266         {
00267             face1[i] = operator[](index);
00268             index = fcIndex(index);
00269         }
00270 
00271         // Collect face2 points
00272         face face2(nPoints2);
00273 
00274         index = minIndex;
00275         for (label i = 0; i < nPoints2; i++)
00276         {
00277             face2[i] = operator[](index);
00278             index = fcIndex(index);
00279         }
00280 
00281         // Split faces
00282         face1.split(mode, points, triI, quadI, triFaces, quadFaces);
00283         face2.split(mode, points, triI, quadI, triFaces, quadFaces);
00284     }
00285 
00286     return (triI + quadI - oldIndices);
00287 }
00288 
00289 
00290 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00291 
00292 Foam::face::face(const triFace& f)
00293 :
00294     labelList(f)
00295 {}
00296 
00297 
00298 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
00299 
00300 
00301 // return
00302 //   0: no match
00303 //  +1: identical
00304 //  -1: same face, but different orientation
00305 int Foam::face::compare(const face& a, const face& b)
00306 {
00307     // Basic rule: we assume that the sequence of labels in each list
00308     // will be circular in the same order (but not necessarily in the
00309     // same direction or from the same starting point).
00310 
00311     // Trivial reject: faces are different size
00312     label sizeA = a.size();
00313     label sizeB = b.size();
00314 
00315     if (sizeA != sizeB)
00316     {
00317         return 0;
00318     }
00319 
00320 
00321     // Full list comparison
00322     const label firstA = a[0];
00323     label Bptr = -1;
00324 
00325     forAll (b, i)
00326     {
00327         if (b[i] == firstA)
00328         {
00329             Bptr = i;        // 'found match' at element 'i'
00330             break;
00331         }
00332     }
00333 
00334     // If no match was found, return 0
00335     if (Bptr < 0)
00336     {
00337         return 0;
00338     }
00339 
00340     // Now we must look for the direction, if any
00341     label secondA = a[1];
00342 
00343     if (sizeA > 1 && (secondA == firstA || firstA == a[sizeA - 1]))
00344     {
00345         face ca = a;
00346         ca.collapse();
00347 
00348         face cb = b;
00349         cb.collapse();
00350 
00351         return face::compare(ca, cb);
00352     }
00353 
00354     int dir = 0;
00355 
00356     // Check whether at top of list
00357     Bptr++;
00358     if (Bptr == b.size())
00359     {
00360         Bptr = 0;
00361     }
00362 
00363     // Test whether upward label matches second A label
00364     if (b[Bptr] == secondA)
00365     {
00366         // Yes - direction is 'up'
00367         dir = 1;
00368     }
00369     else
00370     {
00371         // No - so look downwards, checking whether at bottom of list
00372         Bptr -= 2;
00373 
00374         if (Bptr < 0)
00375         {
00376             // wraparound
00377             Bptr += b.size();
00378         }
00379 
00380         // Test whether downward label matches second A label
00381         if (b[Bptr] == secondA)
00382         {
00383             // Yes - direction is 'down'
00384             dir = -1;
00385         }
00386     }
00387 
00388     // Check whether a match was made at all, and exit 0 if not
00389     if (dir == 0)
00390     {
00391         return 0;
00392     }
00393 
00394     // Decrement size by 2 to account for first searches
00395     sizeA -= 2;
00396 
00397     // We now have both direction of search and next element
00398     // to search, so we can continue search until no more points.
00399     label Aptr = 1;
00400     if (dir > 0)
00401     {
00402         while (sizeA--)
00403         {
00404             Aptr++;
00405             if (Aptr >= a.size())
00406             {
00407                 Aptr = 0;
00408             }
00409 
00410             Bptr++;
00411             if (Bptr >= b.size())
00412             {
00413                 Bptr = 0;
00414             }
00415 
00416             if (a[Aptr] != b[Bptr])
00417             {
00418                 return 0;
00419             }
00420         }
00421     }
00422     else
00423     {
00424         while (sizeA--)
00425         {
00426             Aptr++;
00427             if (Aptr >= a.size())
00428             {
00429                 Aptr = 0;
00430             }
00431 
00432             Bptr--;
00433             if (Bptr < 0)
00434             {
00435                 Bptr = b.size() - 1;
00436             }
00437 
00438             if (a[Aptr] != b[Bptr])
00439             {
00440                 return 0;
00441             }
00442         }
00443     }
00444 
00445     // They must be equal - return direction
00446     return dir;
00447 }
00448 
00449 
00450 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00451 
00452 
00453 Foam::label Foam::face::collapse()
00454 {
00455     if (size() > 1)
00456     {
00457         label ci = 0;
00458         for (label i=1; i<size(); i++)
00459         {
00460             if (operator[](i) != operator[](ci))
00461             {
00462                 operator[](++ci) = operator[](i);
00463             }
00464         }
00465 
00466         if (operator[](ci) != operator[](0))
00467         {
00468             ci++;
00469         }
00470 
00471         setSize(ci);
00472     }
00473 
00474     return size();
00475 }
00476 
00477 
00478 Foam::point Foam::face::centre(const pointField& meshPoints) const
00479 {
00480     // Calculate the centre by breaking the face into triangles and
00481     // area-weighted averaging their centres
00482 
00483     // If the face is a triangle, do a direct calculation
00484     if (size() == 3)
00485     {
00486         return
00487             (1.0/3.0)
00488            *(
00489                meshPoints[operator[](0)]
00490              + meshPoints[operator[](1)]
00491              + meshPoints[operator[](2)]
00492             );
00493     }
00494 
00495     label nPoints = size();
00496 
00497     point centrePoint = point::zero;
00498     for (register label pI=0; pI<nPoints; pI++)
00499     {
00500         centrePoint += meshPoints[operator[](pI)];
00501     }
00502     centrePoint /= nPoints;
00503 
00504     scalar sumA = 0;
00505     vector sumAc = vector::zero;
00506 
00507     for (register label pI=0; pI<nPoints; pI++)
00508     {
00509         const point& nextPoint = meshPoints[operator[]((pI + 1) % nPoints)];
00510 
00511         // Calculate 3*triangle centre
00512         vector ttc
00513         (
00514             meshPoints[operator[](pI)]
00515           + nextPoint
00516           + centrePoint
00517         );
00518 
00519         // Calculate 2*triangle area
00520         scalar ta = Foam::mag
00521         (
00522             (meshPoints[operator[](pI)] - centrePoint)
00523           ^ (nextPoint - centrePoint)
00524         );
00525 
00526         sumA += ta;
00527         sumAc += ta*ttc;
00528     }
00529 
00530     if (sumA > VSMALL)
00531     {
00532         return sumAc/(3*sumA);
00533     }
00534     else
00535     {
00536         return centrePoint;
00537     }
00538 }
00539 
00540 
00541 Foam::vector Foam::face::normal(const pointField& p) const
00542 {
00543     // Calculate the normal by summing the face triangle normals.
00544     // Changed to deal with small concavity by using a central decomposition
00545     //
00546 
00547     // If the face is a triangle, do a direct calculation to avoid round-off
00548     // error-related problems
00549     //
00550     if (size() == 3)
00551     {
00552         return triPointRef
00553         (
00554             p[operator[](0)],
00555             p[operator[](1)],
00556             p[operator[](2)]
00557         ).normal();
00558     }
00559 
00560     label nPoints = size();
00561 
00562     register label pI;
00563 
00564     point centrePoint = vector::zero;
00565     for (pI = 0; pI < nPoints; pI++)
00566     {
00567         centrePoint += p[operator[](pI)];
00568     }
00569     centrePoint /= nPoints;
00570 
00571     vector n = vector::zero;
00572 
00573     point nextPoint = centrePoint;
00574 
00575     for (pI = 0; pI < nPoints; pI++)
00576     {
00577         if (pI < nPoints - 1)
00578         {
00579             nextPoint = p[operator[](pI + 1)];
00580         }
00581         else
00582         {
00583             nextPoint = p[operator[](0)];
00584         }
00585 
00586         // Note: for best accuracy, centre point always comes last
00587         //
00588         n += triPointRef
00589         (
00590             p[operator[](pI)],
00591             nextPoint,
00592             centrePoint
00593         ).normal();
00594     }
00595 
00596     return n;
00597 }
00598 
00599 
00600 Foam::face Foam::face::reverseFace() const
00601 {
00602     // reverse the label list and return
00603     // The starting points of the original and reverse face are identical.
00604 
00605     const labelList& f = *this;
00606     labelList newList(size());
00607 
00608     newList[0] = f[0];
00609 
00610     for (label pointI = 1; pointI < newList.size(); pointI++)
00611     {
00612         newList[pointI] = f[size() - pointI];
00613     }
00614 
00615     return face(xferMove(newList));
00616 }
00617 
00618 
00619 Foam::label Foam::face::which(const label globalIndex) const
00620 {
00621     label pointInFace = -1;
00622     const labelList& f = *this;
00623 
00624     forAll (f, i)
00625     {
00626         if (f[i] == globalIndex)
00627         {
00628             pointInFace = i;
00629             break;
00630         }
00631     }
00632 
00633     return pointInFace;
00634 }
00635 
00636 
00637 Foam::scalar Foam::face::sweptVol
00638 (
00639     const pointField& oldPoints,
00640     const pointField& newPoints
00641 ) const
00642 {
00643     scalar sv = 0;
00644 
00645     // Calculate the swept volume by breaking the face into triangles and
00646     // summing their swept volumes.
00647     // Changed to deal with small concavity by using a central decomposition
00648 
00649     point centreOldPoint = centre(oldPoints);
00650     point centreNewPoint = centre(newPoints);
00651 
00652     label nPoints = size();
00653 
00654     point nextOldPoint = centreOldPoint;
00655     point nextNewPoint = centreNewPoint;
00656 
00657     register label pI;
00658 
00659     for (pI = 0; pI < nPoints; pI++)
00660     {
00661         if (pI < nPoints - 1)
00662         {
00663             nextOldPoint = oldPoints[operator[](pI + 1)];
00664             nextNewPoint = newPoints[operator[](pI + 1)];
00665         }
00666         else
00667         {
00668             nextOldPoint = oldPoints[operator[](0)];
00669             nextNewPoint = newPoints[operator[](0)];
00670         }
00671 
00672         // Note: for best accuracy, centre point always comes last
00673         sv += triPointRef
00674               (
00675                   centreOldPoint,
00676                   oldPoints[operator[](pI)],
00677                   nextOldPoint
00678               ).sweptVol
00679               (
00680                   triPointRef
00681                   (
00682                       centreNewPoint,
00683                       newPoints[operator[](pI)],
00684                       nextNewPoint
00685                   )
00686               );
00687     }
00688 
00689     return sv;
00690 }
00691 
00692 
00693 Foam::edgeList Foam::face::edges() const
00694 {
00695     const labelList& points = *this;
00696 
00697     edgeList e(points.size());
00698 
00699     label pointI;
00700 
00701     for (pointI = 0; pointI < points.size() - 1; pointI++)
00702     {
00703         e[pointI] = edge(points[pointI], points[pointI + 1]);
00704     }
00705 
00706     // add last edge
00707     e[points.size() - 1] = edge(points[points.size() - 1], points[0]);
00708 
00709     return e;
00710 }
00711 
00712 
00713 int Foam::face::edgeDirection(const edge& e) const
00714 {
00715     forAll (*this, i)
00716     {
00717         if (operator[](i) == e.start())
00718         {
00719             if (operator[](rcIndex(i)) == e.end())
00720             {
00721                 // reverse direction
00722                 return -1;
00723             }
00724             else if (operator[](fcIndex(i)) == e.end())
00725             {
00726                 // forward direction
00727                 return 1;
00728             }
00729 
00730             // no match
00731             return 0;
00732         }
00733         else if (operator[](i) == e.end())
00734         {
00735             if (operator[](rcIndex(i)) == e.start())
00736             {
00737                 // forward direction
00738                 return 1;
00739             }
00740             else if (operator[](fcIndex(i)) == e.start())
00741             {
00742                 // reverse direction
00743                 return -1;
00744             }
00745 
00746             // no match
00747             return 0;
00748         }
00749     }
00750 
00751     // not found
00752     return 0;
00753 }
00754 
00755 
00756 // Number of triangles directly known from number of vertices
00757 Foam::label Foam::face::nTriangles(const pointField&) const
00758 {
00759     return nTriangles();
00760 }
00761 
00762 
00763 Foam::label Foam::face::triangles
00764 (
00765     const pointField& points,
00766     label& triI,
00767     faceList& triFaces
00768 ) const
00769 {
00770     label quadI = 0;
00771     faceList quadFaces;
00772 
00773     return split(SPLITTRIANGLE, points, triI, quadI, triFaces, quadFaces);
00774 }
00775 
00776 
00777 Foam::label Foam::face::nTrianglesQuads
00778 (
00779     const pointField& points,
00780     label& triI,
00781     label& quadI
00782 ) const
00783 {
00784     faceList triFaces;
00785     faceList quadFaces;
00786 
00787     return split(COUNTQUAD, points, triI, quadI, triFaces, quadFaces);
00788 }
00789 
00790 
00791 Foam::label Foam::face::trianglesQuads
00792 (
00793     const pointField& points,
00794     label& triI,
00795     label& quadI,
00796     faceList& triFaces,
00797     faceList& quadFaces
00798 ) const
00799 {
00800     return split(SPLITQUAD, points, triI, quadI, triFaces, quadFaces);
00801 }
00802 
00803 
00804 // * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
00805 
00806 
00807 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00808 
00809 // ************************ vim: set sw=4 sts=4 et: ************************ //
00810 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines