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

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