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

treeDataFace.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 "treeDataFace.H"
00027 #include <OpenFOAM/polyMesh.H>
00028 #include <meshTools/triangleFuncs.H>
00029 
00030 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00031 
00032 defineTypeNameAndDebug(Foam::treeDataFace, 0);
00033 
00034 Foam::scalar Foam::treeDataFace::tolSqr = sqr(1E-6);
00035 
00036 
00037 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00038 
00039 Foam::treeBoundBox Foam::treeDataFace::calcBb(const label faceI) const
00040 {
00041     const pointField& points = mesh_.points();
00042 
00043     const face& f = mesh_.faces()[faceI];
00044 
00045     treeBoundBox bb(points[f[0]], points[f[0]]);
00046 
00047     for (label fp = 1; fp < f.size(); fp++)
00048     {
00049         const point& p = points[f[fp]];
00050 
00051         bb.min() = min(bb.min(), p);
00052         bb.max() = max(bb.max(), p);
00053     }
00054     return bb;
00055 }
00056 
00057 
00058 void Foam::treeDataFace::update()
00059 {
00060     forAll(faceLabels_, i)
00061     {
00062         isTreeFace_.set(faceLabels_[i], 1);
00063     }
00064 
00065     if (cacheBb_)
00066     {
00067         bbs_.setSize(faceLabels_.size());
00068 
00069         forAll(faceLabels_, i)
00070         {
00071             bbs_[i] = calcBb(faceLabels_[i]);
00072         }
00073     }
00074 }
00075 
00076 
00077 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00078 
00079 // Construct from components
00080 Foam::treeDataFace::treeDataFace
00081 (
00082     const bool cacheBb,
00083     const primitiveMesh& mesh,
00084     const labelList& faceLabels
00085 )
00086 :
00087     mesh_(mesh),
00088     faceLabels_(faceLabels),
00089     isTreeFace_(mesh.nFaces(), 0),
00090     cacheBb_(cacheBb)
00091 {
00092     update();
00093 }
00094 
00095 
00096 Foam::treeDataFace::treeDataFace
00097 (
00098     const bool cacheBb,
00099     const primitiveMesh& mesh
00100 )
00101 :
00102     mesh_(mesh),
00103     faceLabels_(identity(mesh_.nFaces())),
00104     isTreeFace_(mesh.nFaces(), 0),
00105     cacheBb_(cacheBb)
00106 {
00107     update();
00108 }
00109 
00110 
00111 Foam::treeDataFace::treeDataFace
00112 (
00113     const bool cacheBb,
00114     const polyPatch& patch
00115 )
00116 :
00117     mesh_(patch.boundaryMesh().mesh()),
00118     faceLabels_
00119     (
00120         identity(patch.size())
00121       + patch.start()
00122     ),
00123     isTreeFace_(mesh_.nFaces(), 0),
00124     cacheBb_(cacheBb)
00125 {
00126     update();
00127 }
00128 
00129 
00130 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00131 
00132 Foam::pointField Foam::treeDataFace::points() const
00133 {
00134     pointField cc(faceLabels_.size());
00135 
00136     forAll(faceLabels_, i)
00137     {
00138         cc[i] = mesh_.faceCentres()[faceLabels_[i]];
00139     }
00140 
00141     return cc;
00142 }
00143 
00144 
00145 //- Get type (inside,outside,mixed,unknown) of point w.r.t. surface.
00146 //  Only makes sense for closed surfaces.
00147 Foam::label Foam::treeDataFace::getVolumeType
00148 (
00149     const indexedOctree<treeDataFace>& oc,
00150     const point& sample
00151 ) const
00152 {
00153     // Need to determine whether sample is 'inside' or 'outside'
00154     // Done by finding nearest face. This gives back a face which is
00155     // guaranteed to contain nearest point. This point can be
00156     // - in interior of face: compare to face normal
00157     // - on edge of face: compare to edge normal
00158     // - on point of face: compare to point normal
00159     // Unfortunately the octree does not give us back the intersection point
00160     // or where on the face it has hit so we have to recreate all that
00161     // information.
00162 
00163 
00164     // Find nearest face to sample
00165     pointIndexHit info = oc.findNearest(sample, sqr(GREAT));
00166 
00167     if (info.index() == -1)
00168     {
00169         FatalErrorIn
00170         (
00171             "treeDataFace::getSampleType"
00172             "(indexedOctree<treeDataFace>&, const point&)"
00173         )   << "Could not find " << sample << " in octree."
00174             << abort(FatalError);
00175     }
00176 
00177 
00178     // Get actual intersection point on face
00179     label faceI = faceLabels_[info.index()];
00180 
00181     if (debug & 2)
00182     {
00183         Pout<< "getSampleType : sample:" << sample
00184             << " nearest face:" << faceI;
00185     }
00186 
00187     const pointField& points = mesh_.points();
00188 
00189     // Retest to classify where on face info is. Note: could be improved. We
00190     // already have point.
00191 
00192     const face& f = mesh_.faces()[faceI];
00193     const vector& area = mesh_.faceAreas()[faceI];
00194     const point& fc = mesh_.faceCentres()[faceI];
00195 
00196     pointHit curHit = f.nearestPoint(sample, points);
00197     const point& curPt = curHit.rawPoint();
00198 
00199     //
00200     // 1] Check whether sample is above face
00201     //
00202 
00203     if (curHit.hit())
00204     {
00205         // Nearest point inside face. Compare to face normal.
00206 
00207         if (debug & 2)
00208         {
00209             Pout<< " -> face hit:" << curPt
00210                 << " comparing to face normal " << area << endl;
00211         }
00212         return indexedOctree<treeDataFace>::getSide(area, sample - curPt);
00213     }
00214 
00215     if (debug & 2)
00216     {
00217         Pout<< " -> face miss:" << curPt;
00218     }
00219 
00220     //
00221     // 2] Check whether intersection is on one of the face vertices or
00222     //    face centre
00223     //
00224 
00225     const scalar typDimSqr = mag(area) + VSMALL;
00226 
00227     forAll(f, fp)
00228     {
00229         if ((magSqr(points[f[fp]] - curPt)/typDimSqr) < tolSqr)
00230         {
00231             // Face intersection point equals face vertex fp
00232 
00233             // Calculate point normal (wrong: uses face normals instead of
00234             // triangle normals)
00235             const labelList& pFaces = mesh_.pointFaces()[f[fp]];
00236 
00237             vector pointNormal(vector::zero);
00238 
00239             forAll(pFaces, i)
00240             {
00241                 if (isTreeFace_.get(pFaces[i]) == 1)
00242                 {
00243                     vector n = mesh_.faceAreas()[pFaces[i]];
00244                     n /= mag(n) + VSMALL;
00245 
00246                     pointNormal += n;
00247                 }
00248             }
00249 
00250             if (debug & 2)
00251             {
00252                     Pout<< " -> face point hit :" << points[f[fp]]
00253                         << " point normal:" << pointNormal
00254                         << " distance:"
00255                         << magSqr(points[f[fp]] - curPt)/typDimSqr << endl;
00256             }
00257             return indexedOctree<treeDataFace>::getSide
00258             (
00259                 pointNormal,
00260                 sample - curPt
00261             );
00262         }
00263     }
00264     if ((magSqr(fc - curPt)/typDimSqr) < tolSqr)
00265     {
00266         // Face intersection point equals face centre. Normal at face centre
00267         // is already average of face normals
00268 
00269         if (debug & 2)
00270         {
00271             Pout<< " -> centre hit:" << fc
00272                 << " distance:" << magSqr(fc - curPt)/typDimSqr << endl;
00273         }
00274 
00275         return indexedOctree<treeDataFace>::getSide(area,  sample - curPt);
00276     }
00277 
00278 
00279 
00280     //
00281     // 3] Get the 'real' edge the face intersection is on
00282     //
00283 
00284     const labelList& myEdges = mesh_.faceEdges()[faceI];
00285 
00286     forAll(myEdges, myEdgeI)
00287     {
00288         const edge& e = mesh_.edges()[myEdges[myEdgeI]];
00289 
00290         pointHit edgeHit =
00291             line<point, const point&>
00292             (
00293                 points[e.start()],
00294                 points[e.end()]
00295             ).nearestDist(sample);
00296 
00297 
00298         if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
00299         {
00300             // Face intersection point lies on edge e
00301 
00302             // Calculate edge normal (wrong: uses face normals instead of
00303             // triangle normals)
00304             const labelList& eFaces = mesh_.edgeFaces()[myEdges[myEdgeI]];
00305 
00306             vector edgeNormal(vector::zero);
00307 
00308             forAll(eFaces, i)
00309             {
00310                 if (isTreeFace_.get(eFaces[i]) == 1)
00311                 {
00312                     vector n = mesh_.faceAreas()[eFaces[i]];
00313                     n /= mag(n) + VSMALL;
00314 
00315                     edgeNormal += n;
00316                 }
00317             }
00318 
00319             if (debug & 2)
00320             {
00321                 Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
00322                     << " comparing to edge normal:" << edgeNormal
00323                     << endl;
00324             }
00325 
00326             // Found face intersection point on this edge. Compare to edge
00327             // normal
00328             return indexedOctree<treeDataFace>::getSide
00329             (
00330                 edgeNormal,
00331                 sample - curPt
00332             );
00333         }
00334     }
00335 
00336 
00337     //
00338     // 4] Get the internal edge the face intersection is on
00339     //
00340 
00341     forAll(f, fp)
00342     {
00343         pointHit edgeHit = line<point, const point&>
00344         (
00345             points[f[fp]],
00346             fc
00347         ).nearestDist(sample);
00348 
00349         if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
00350         {
00351             // Face intersection point lies on edge between two face triangles
00352 
00353             // Calculate edge normal as average of the two triangle normals
00354             vector e = points[f[fp]] - fc;
00355             vector ePrev = points[f[f.rcIndex(fp)]] - fc;
00356             vector eNext = points[f[f.fcIndex(fp)]] - fc;
00357 
00358             vector nLeft = ePrev ^ e;
00359             nLeft /= mag(nLeft) + VSMALL;
00360 
00361             vector nRight = e ^ eNext;
00362             nRight /= mag(nRight) + VSMALL;
00363 
00364             if (debug & 2)
00365             {
00366                 Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
00367                     << " comparing to edge normal "
00368                     << 0.5*(nLeft + nRight)
00369                     << endl;
00370             }
00371 
00372             // Found face intersection point on this edge. Compare to edge
00373             // normal
00374             return indexedOctree<treeDataFace>::getSide
00375             (
00376                 0.5*(nLeft + nRight),
00377                 sample - curPt
00378             );
00379         }
00380     }
00381 
00382     if (debug & 2)
00383     {
00384         Pout<< "Did not find sample " << sample
00385             << " anywhere related to nearest face " << faceI << endl
00386             << "Face:";
00387 
00388         forAll(f, fp)
00389         {
00390             Pout<< "    vertex:" << f[fp] << "  coord:" << points[f[fp]]
00391                 << endl;
00392         }
00393     }
00394 
00395     // Can't determine status of sample with respect to nearest face.
00396     // Either
00397     // - tolerances are wrong. (if e.g. face has zero area)
00398     // - or (more likely) surface is not closed.
00399 
00400     return indexedOctree<treeDataFace>::UNKNOWN;
00401 }
00402 
00403 
00404 // Check if any point on shape is inside cubeBb.
00405 bool Foam::treeDataFace::overlaps
00406 (
00407     const label index,
00408     const treeBoundBox& cubeBb
00409 ) const
00410 {
00411     // 1. Quick rejection: bb does not intersect face bb at all
00412     if (cacheBb_)
00413     {
00414         if (!cubeBb.overlaps(bbs_[index]))
00415         {
00416             return false;
00417         }
00418     }
00419     else
00420     {
00421         if (!cubeBb.overlaps(calcBb(faceLabels_[index])))
00422         {
00423             return false;
00424         }
00425     }
00426 
00427     const pointField& points = mesh_.points();
00428 
00429 
00430     // 2. Check if one or more face points inside
00431     label faceI = faceLabels_[index];
00432 
00433     const face& f = mesh_.faces()[faceI];
00434 
00435     forAll(f, fp)
00436     {
00437         if (cubeBb.contains(points[f[fp]]))
00438         {
00439             return true;
00440         }
00441     }
00442 
00443     // 3. Difficult case: all points are outside but connecting edges might
00444     // go through cube. Use triangle-bounding box intersection.
00445     const point& fc = mesh_.faceCentres()[faceI];
00446 
00447     forAll(f, fp)
00448     {
00449         bool triIntersects = triangleFuncs::intersectBb
00450         (
00451             points[f[fp]],
00452             points[f[f.fcIndex(fp)]],
00453             fc,
00454             cubeBb
00455         );
00456 
00457         if (triIntersects)
00458         {
00459             return true;
00460         }
00461     }
00462     return false;
00463 }
00464 
00465 
00466 // Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
00467 // nearestPoint.
00468 void Foam::treeDataFace::findNearest
00469 (
00470     const labelList& indices,
00471     const point& sample,
00472 
00473     scalar& nearestDistSqr,
00474     label& minIndex,
00475     point& nearestPoint
00476 ) const
00477 {
00478     forAll(indices, i)
00479     {
00480         label index = indices[i];
00481 
00482         const face& f = mesh_.faces()[faceLabels_[index]];
00483 
00484         pointHit nearHit = f.nearestPoint(sample, mesh_.points());
00485         scalar distSqr = sqr(nearHit.distance());
00486 
00487         if (distSqr < nearestDistSqr)
00488         {
00489             nearestDistSqr = distSqr;
00490             minIndex = index;
00491             nearestPoint = nearHit.rawPoint();
00492         }
00493     }
00494 }
00495 
00496 
00497 bool Foam::treeDataFace::intersects
00498 (
00499     const label index,
00500     const point& start,
00501     const point& end,
00502     point& intersectionPoint
00503 ) const
00504 {
00505     // Do quick rejection test
00506     if (cacheBb_)
00507     {
00508         const treeBoundBox& faceBb = bbs_[index];
00509 
00510         if ((faceBb.posBits(start) & faceBb.posBits(end)) != 0)
00511         {
00512             // start and end in same block outside of faceBb.
00513             return false;
00514         }
00515     }
00516 
00517     label faceI = faceLabels_[index];
00518 
00519     const vector dir(end - start);
00520 
00521     pointHit inter = mesh_.faces()[faceI].intersection
00522     (
00523         start,
00524         dir,
00525         mesh_.faceCentres()[faceI],
00526         mesh_.points(),
00527         intersection::HALF_RAY
00528     );
00529 
00530     if (inter.hit() && inter.distance() <= 1)
00531     {
00532         // Note: no extra test on whether intersection is in front of us
00533         // since using half_ray
00534         intersectionPoint = inter.hitPoint();
00535         return true;
00536     }
00537     else
00538     {
00539         return false;
00540     }
00541 }
00542 
00543 
00544 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines