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

octreeDataFace.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 "octreeDataFace.H"
00027 #include <OpenFOAM/labelList.H>
00028 #include <OpenFOAM/polyMesh.H>
00029 #include "octree.H"
00030 #include <OpenFOAM/polyPatch.H>
00031 #include <meshTools/triangleFuncs.H>
00032 #include <OpenFOAM/linePointRef.H>
00033 
00034 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00035 
00036 defineTypeNameAndDebug(Foam::octreeDataFace, 0);
00037 
00038 Foam::scalar Foam::octreeDataFace::tol(1E-6);
00039 
00040 
00041 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00042 
00043 void Foam::octreeDataFace::calcBb()
00044 {
00045     allBb_.setSize(meshFaces_.size());
00046     allBb_ = treeBoundBox::invertedBox;
00047 
00048     forAll (meshFaces_, i)
00049     {
00050         // Update bb of face
00051         treeBoundBox& myBb = allBb_[i];
00052 
00053         const face& f = mesh_.faces()[meshFaces_[i]];
00054 
00055         forAll(f, faceVertexI)
00056         {
00057             const point& coord = mesh_.points()[f[faceVertexI]];
00058 
00059             myBb.min() = min(myBb.min(), coord);
00060             myBb.max() = max(myBb.max(), coord);
00061         }
00062     }
00063 }
00064 
00065 
00066 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00067 
00068 // Construct from selected mesh faces
00069 Foam::octreeDataFace::octreeDataFace
00070 (
00071     const primitiveMesh& mesh,
00072     const labelList& meshFaces,
00073     const treeBoundBoxList& allBb
00074 )
00075 :
00076     mesh_(mesh),
00077     meshFaces_(meshFaces),
00078     allBb_(allBb)
00079 {}
00080 
00081 
00082 // Construct from selected mesh faces. Bounding box calculated.
00083 Foam::octreeDataFace::octreeDataFace
00084 (
00085     const primitiveMesh& mesh,
00086     const labelList& meshFaces
00087 )
00088 :
00089     mesh_(mesh),
00090     meshFaces_(meshFaces),
00091     allBb_(meshFaces_.size())
00092 {
00093     // Generate tight fitting bounding box
00094     calcBb();
00095 }
00096 
00097 
00098 // Construct from selected mesh faces
00099 Foam::octreeDataFace::octreeDataFace
00100 (
00101     const primitiveMesh& mesh,
00102     const UList<const labelList*>& meshFaceListPtrs,
00103     const UList<const treeBoundBoxList*>& bbListPtrs
00104 )
00105 :
00106     mesh_(mesh),
00107     meshFaces_(0),
00108     allBb_(0)
00109 {
00110     label faceI = 0;
00111 
00112     forAll(meshFaceListPtrs, listI)
00113     {
00114         faceI += meshFaceListPtrs[listI]->size();
00115     }
00116 
00117     meshFaces_.setSize(faceI);
00118     allBb_.setSize(faceI);
00119 
00120     faceI = 0;
00121 
00122     forAll(meshFaceListPtrs, listI)
00123     {
00124         const labelList& meshFaces = *meshFaceListPtrs[listI];
00125         const treeBoundBoxList& allBb = *bbListPtrs[listI];
00126 
00127         forAll(meshFaces, meshFaceI)
00128         {
00129             meshFaces_[faceI] = meshFaces[meshFaceI];
00130             allBb_[faceI] = allBb[meshFaceI];
00131             faceI++;
00132         }
00133     }
00134 }
00135 
00136 
00137 // Construct from selected mesh faces. Bounding box calculated.
00138 Foam::octreeDataFace::octreeDataFace
00139 (
00140     const primitiveMesh& mesh,
00141     const UList<const labelList*>& meshFaceListPtrs
00142 )
00143 :
00144     mesh_(mesh),
00145     meshFaces_(0)
00146 {
00147     label faceI = 0;
00148 
00149     forAll(meshFaceListPtrs, listI)
00150     {
00151         faceI += meshFaceListPtrs[listI]->size();
00152     }
00153 
00154     meshFaces_.setSize(faceI);
00155 
00156     faceI = 0;
00157 
00158     forAll(meshFaceListPtrs, listI)
00159     {
00160         const labelList& meshFaces = *meshFaceListPtrs[listI];
00161 
00162         forAll(meshFaces, meshFaceI)
00163         {
00164             meshFaces_[faceI++] = meshFaces[meshFaceI];
00165         }
00166     }
00167 
00168     // Generate tight fitting bounding box
00169     calcBb();
00170 }
00171 
00172 
00173 // Construct from all faces in polyPatch. Bounding box calculated.
00174 Foam::octreeDataFace::octreeDataFace(const polyPatch& patch)
00175 :
00176     mesh_(patch.boundaryMesh().mesh()),
00177     meshFaces_(patch.size())
00178 {
00179     forAll(patch, patchFaceI)
00180     {
00181         meshFaces_[patchFaceI] = patch.start() + patchFaceI;
00182     }
00183 
00184     // Generate tight fitting bounding box
00185     calcBb();
00186 }
00187 
00188 
00189 // Construct from primitiveMesh. Inserts all boundary faces.
00190 Foam::octreeDataFace::octreeDataFace(const primitiveMesh& mesh)
00191 :
00192     mesh_(mesh),
00193     meshFaces_(0),
00194     allBb_(0)
00195 {
00196     // Size storage
00197     meshFaces_.setSize(mesh_.nFaces() - mesh_.nInternalFaces());
00198 
00199     // Set info for all boundary faces.
00200     label boundaryFaceI = 0;
00201 
00202     for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
00203     {
00204         meshFaces_[boundaryFaceI++] = faceI;
00205     }
00206 
00207     // Generate tight fitting bounding box
00208     calcBb();
00209 }
00210 
00211 
00212 // Construct as copy
00213 Foam::octreeDataFace::octreeDataFace(const octreeDataFace& shapes)
00214 :
00215     mesh_(shapes.mesh()),
00216     meshFaces_(shapes.meshFaces()),
00217     allBb_(shapes.allBb())
00218 {}
00219 
00220 
00221 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
00222 
00223 Foam::octreeDataFace::~octreeDataFace()
00224 {}
00225 
00226 
00227 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00228 
00229 Foam::label Foam::octreeDataFace::getSampleType
00230 (
00231     const octree<octreeDataFace>& oc,
00232     const point& sample
00233 ) const
00234 {
00235     // Need to determine whether sample is 'inside' or 'outside'
00236     // Done by finding nearest face. This gives back a face which is
00237     // guaranteed to contain nearest point. This point can be
00238     // - in interior of face: compare to face normal
00239     // - on edge of face: compare to edge normal
00240     // - on point of face: compare to point normal
00241     // Unfortunately the octree does not give us back the intersection point
00242     // or where on the face it has hit so we have to recreate all that
00243     // information.
00244 
00245     treeBoundBox tightest(treeBoundBox::greatBox);
00246     scalar tightestDist(treeBoundBox::great);
00247     // Find nearest face to sample
00248     label index = oc.findNearest(sample, tightest, tightestDist);
00249 
00250     if (index == -1)
00251     {
00252         FatalErrorIn
00253         (
00254             "octreeDataFace::getSampleType"
00255             "(octree<octreeDataFace>&, const point&)"
00256         )   << "Could not find " << sample << " in octree."
00257             << abort(FatalError);
00258     }
00259 
00260 
00261     // Get actual intersection point on face
00262     label faceI = meshFaces_[index];
00263 
00264     if (debug & 2)
00265     {
00266         Pout<< "getSampleType : sample:" << sample
00267             << " nearest face:" << faceI;
00268     }
00269 
00270     const face& f = mesh_.faces()[faceI];
00271 
00272     const pointField& points = mesh_.points();
00273 
00274     pointHit curHit = f.nearestPoint(sample, points);
00275 
00276     //
00277     // 1] Check whether sample is above face
00278     //
00279 
00280     if (curHit.hit())
00281     {
00282         // Simple case. Compare to face normal.
00283 
00284         if (debug & 2)
00285         {
00286             Pout<< " -> face hit:" << curHit.hitPoint()
00287                 << " comparing to face normal " << mesh_.faceAreas()[faceI]
00288                 << endl;
00289         }
00290         return octree<octreeDataFace>::getVolType
00291         (
00292             mesh_.faceAreas()[faceI],
00293             sample - curHit.hitPoint()
00294         );
00295     }
00296 
00297     if (debug & 2)
00298     {
00299         Pout<< " -> face miss:" << curHit.missPoint();
00300     }
00301 
00302     //
00303     // 2] Check whether intersection is on one of the face vertices or
00304     //    face centre
00305     //
00306 
00307     scalar typDim = sqrt(mag(mesh_.faceAreas()[faceI])) + VSMALL;
00308 
00309     forAll(f, fp)
00310     {
00311         if ((mag(points[f[fp]] - curHit.missPoint())/typDim) < tol)
00312         {
00313             // Face intersection point equals face vertex fp
00314 
00315             // Calculate point normal (wrong: uses face normals instead of
00316             // triangle normals)
00317             const labelList& myFaces = mesh_.pointFaces()[f[fp]];
00318 
00319             vector pointNormal(vector::zero);
00320 
00321             forAll(myFaces, myFaceI)
00322             {
00323                 if (myFaces[myFaceI] >= mesh_.nInternalFaces())
00324                 {
00325                     vector n = mesh_.faceAreas()[myFaces[myFaceI]];
00326                     n /= mag(n) + VSMALL;
00327 
00328                     pointNormal += n;
00329                 }
00330             }
00331 
00332             if (debug & 2)
00333             {
00334                     Pout<< " -> face point hit :" << points[f[fp]]
00335                         << " point normal:" << pointNormal
00336                         << " distance:"
00337                         << mag(points[f[fp]] - curHit.missPoint())/typDim
00338                         << endl;
00339             }
00340             return octree<octreeDataFace>::getVolType
00341             (
00342                 pointNormal,
00343                 sample - curHit.missPoint()
00344             );
00345         }
00346     }
00347     if ((mag(mesh_.faceCentres()[faceI] - curHit.missPoint())/typDim) < tol)
00348     {
00349         // Face intersection point equals face centre. Normal at face centre
00350         // is already average of face normals
00351 
00352         if (debug & 2)
00353         {
00354             Pout<< " -> centre hit:" << mesh_.faceCentres()[faceI]
00355                 << " distance:"
00356                 << mag(mesh_.faceCentres()[faceI] - curHit.missPoint())/typDim
00357                 << endl;
00358         }
00359 
00360         return octree<octreeDataFace>::getVolType
00361         (
00362             mesh_.faceAreas()[faceI],
00363             sample - curHit.missPoint()
00364         );
00365     }
00366 
00367 
00368     //
00369     // 3] Get the 'real' edge the face intersection is on
00370     //
00371 
00372     const labelList& myEdges = mesh_.faceEdges()[faceI];
00373 
00374     forAll(myEdges, myEdgeI)
00375     {
00376         const edge& e = mesh_.edges()[myEdges[myEdgeI]];
00377 
00378         pointHit edgeHit = line<point, const point&>
00379         (
00380             points[e.start()],
00381             points[e.end()]
00382         ).nearestDist(sample);
00383 
00384 
00385         if ((mag(edgeHit.rawPoint() - curHit.missPoint())/typDim) < tol)
00386         {
00387             // Face intersection point lies on edge e
00388 
00389             // Calculate edge normal (wrong: uses face normals instead of
00390             // triangle normals)
00391             const labelList& myFaces = mesh_.edgeFaces()[myEdges[myEdgeI]];
00392 
00393             vector edgeNormal(vector::zero);
00394 
00395             forAll(myFaces, myFaceI)
00396             {
00397                 if (myFaces[myFaceI] >= mesh_.nInternalFaces())
00398                 {
00399                     vector n = mesh_.faceAreas()[myFaces[myFaceI]];
00400                     n /= mag(n) + VSMALL;
00401 
00402                     edgeNormal += n;
00403                 }
00404             }
00405 
00406             if (debug & 2)
00407             {
00408                 Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
00409                     << " comparing to edge normal:" << edgeNormal
00410                     << endl;
00411             }
00412 
00413             // Found face intersection point on this edge. Compare to edge
00414             // normal
00415             return octree<octreeDataFace>::getVolType
00416             (
00417                 edgeNormal,
00418                 sample - curHit.missPoint()
00419             );
00420         }
00421     }
00422 
00423 
00424     //
00425     // 4] Get the internal edge the face intersection is on
00426     //
00427 
00428     forAll(f, fp)
00429     {
00430         pointHit edgeHit =
00431             line<point, const point&>
00432             (
00433                 points[f[fp]],
00434                 mesh_.faceCentres()[faceI]
00435             ).nearestDist(sample);
00436 
00437         if ((mag(edgeHit.rawPoint() - curHit.missPoint())/typDim) < tol)
00438         {
00439             // Face intersection point lies on edge between two face triangles
00440 
00441             // Calculate edge normal as average of the two triangle normals
00442             const label fpPrev = f.rcIndex(fp);
00443             const label fpNext = f.fcIndex(fp);
00444 
00445             vector e = points[f[fp]] - mesh_.faceCentres()[faceI];
00446             vector ePrev = points[f[fpPrev]] - mesh_.faceCentres()[faceI];
00447             vector eNext = points[f[fpNext]] - mesh_.faceCentres()[faceI];
00448 
00449             vector nLeft = ePrev ^ e;
00450             nLeft /= mag(nLeft) + VSMALL;
00451 
00452             vector nRight = e ^ eNext;
00453             nRight /= mag(nRight) + VSMALL;
00454 
00455             if (debug & 2)
00456             {
00457                 Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
00458                     << " comparing to edge normal "
00459                     << 0.5*(nLeft + nRight)
00460                     << endl;
00461             }
00462 
00463             // Found face intersection point on this edge. Compare to edge
00464             // normal
00465             return octree<octreeDataFace>::getVolType
00466             (
00467                 0.5*(nLeft + nRight),
00468                 sample - curHit.missPoint()
00469             );
00470         }
00471     }
00472 
00473     if (debug & 2)
00474     {
00475         Pout<< "Did not find sample " << sample
00476             << " anywhere related to nearest face " << faceI << endl
00477             << "Face:";
00478 
00479         forAll(f, fp)
00480         {
00481             Pout<< "    vertex:" << f[fp] << "  coord:" << points[f[fp]]
00482                 << endl;
00483         }
00484     }
00485 
00486     // Can't determine status of sample with respect to nearest face.
00487     // Either
00488     // - tolerances are wrong. (if e.g. face has zero area)
00489     // - or (more likely) surface is not closed.
00490 
00491     return octree<octreeDataFace>::UNKNOWN;
00492 }
00493 
00494 
00495 bool Foam::octreeDataFace::overlaps
00496 (
00497     const label index,
00498     const treeBoundBox& sampleBb
00499 ) const
00500 {
00501     //return sampleBb.overlaps(allBb_[index]);
00502 
00503     //- Exact test of face intersecting bb
00504 
00505     // 1. Quick rejection: bb does not intersect face bb at all
00506     if (!sampleBb.overlaps(allBb_[index]))
00507     {
00508         return false;
00509     }
00510 
00511     // 2. Check if one or more face points inside
00512     label faceI = meshFaces_[index];
00513 
00514     const face& f = mesh_.faces()[faceI];
00515 
00516     const pointField& points = mesh_.points();
00517 
00518     forAll(f, fp)
00519     {
00520         if (sampleBb.contains(points[f[fp]]))
00521         {
00522             return true;
00523         }
00524     }
00525 
00526     // 3. Difficult case: all points are outside but connecting edges might
00527     // go through cube. Use triangle-bounding box intersection.
00528     const point& fc = mesh_.faceCentres()[faceI];
00529 
00530     forAll(f, fp)
00531     {
00532         const label fp1 = f.fcIndex(fp);
00533 
00534         bool triIntersects = triangleFuncs::intersectBb
00535         (
00536             points[f[fp]],
00537             points[f[fp1]],
00538             fc,
00539             sampleBb
00540         );
00541 
00542         if (triIntersects)
00543         {
00544             return true;
00545         }
00546     }
00547     return false;
00548 }
00549 
00550 
00551 bool Foam::octreeDataFace::contains(const label, const point&) const
00552 {
00553     notImplemented
00554     (
00555         "octreeDataFace::contains(const label, const point&)"
00556     );
00557     return false;
00558 }
00559 
00560 
00561 bool Foam::octreeDataFace::intersects
00562 (
00563     const label index,
00564     const point& start,
00565     const point& end,
00566     point& intersectionPoint
00567 ) const
00568 {
00569     label faceI = meshFaces_[index];
00570 
00571     const face& f = mesh_.faces()[faceI];
00572 
00573     const vector dir(end - start);
00574 
00575     // Disable picking up intersections behind us.
00576     scalar oldTol = intersection::setPlanarTol(0.0);
00577 
00578     pointHit inter = f.ray
00579     (
00580         start,
00581         dir,
00582         mesh_.points(),
00583         intersection::HALF_RAY,
00584         intersection::VECTOR
00585     );
00586 
00587     intersection::setPlanarTol(oldTol);
00588 
00589     if (inter.hit() && inter.distance() <= mag(dir))
00590     {
00591         intersectionPoint = inter.hitPoint();
00592 
00593         return true;
00594     }
00595     else
00596     {
00597         return false;
00598     }
00599 }
00600 
00601 
00602 bool Foam::octreeDataFace::findTightest
00603 (
00604     const label index,
00605     const point& sample,
00606     treeBoundBox& tightest
00607 ) const
00608 {
00609     // Get furthest away vertex
00610     point myNear, myFar;
00611     allBb_[index].calcExtremities(sample, myNear, myFar);
00612 
00613     const point dist = myFar - sample;
00614     scalar myFarDist = mag(dist);
00615 
00616     point tightestNear, tightestFar;
00617     tightest.calcExtremities(sample, tightestNear, tightestFar);
00618 
00619     scalar tightestFarDist = mag(tightestFar - sample);
00620 
00621     if (tightestFarDist < myFarDist)
00622     {
00623         // Keep current tightest.
00624         return false;
00625     }
00626     else
00627     {
00628         // Construct bb around sample and myFar
00629         const point dist2(fabs(dist.x()), fabs(dist.y()), fabs(dist.z()));
00630 
00631         tightest.min() = sample - dist2;
00632         tightest.max() = sample + dist2;
00633 
00634         return true;
00635     }
00636 }
00637 
00638 
00639 // Determine numerical value of sign of sample compared to shape at index
00640 Foam::scalar Foam::octreeDataFace::calcSign
00641 (
00642     const label index,
00643     const point& sample,
00644     point& n
00645 ) const
00646 {
00647     label faceI = meshFaces_[index];
00648 
00649     n = mesh_.faceAreas()[faceI];
00650 
00651     n /= mag(n) + VSMALL;
00652 
00653     vector vec = sample - mesh_.faceCentres()[faceI];
00654 
00655     vec /= mag(vec) + VSMALL;
00656 
00657     return n & vec;
00658 }
00659 
00660 
00661 // Calculate nearest point on/in shapei
00662 Foam::scalar Foam::octreeDataFace::calcNearest
00663 (
00664     const label index,
00665     const point& sample,
00666     point& nearest
00667 ) const
00668 {
00669     label faceI = meshFaces_[index];
00670 
00671     const face& f = mesh_.faces()[faceI];
00672 
00673     pointHit nearHit = f.nearestPoint(sample, mesh_.points());
00674 
00675     nearest = nearHit.rawPoint();
00676 
00677     if (debug & 1)
00678     {
00679         const point& ctr = mesh_.faceCentres()[faceI];
00680 
00681         scalar sign = mesh_.faceAreas()[faceI] & (sample - nearest);
00682 
00683         Pout<< "octreeDataFace::calcNearest : "
00684             << "sample:" << sample
00685             << "  index:" << index
00686             << "  faceI:" << faceI
00687             << "  ctr:" << ctr
00688             << "  sign:" << sign
00689             << "  nearest point:" << nearest
00690             << "  distance to face:" << nearHit.distance()
00691             << endl;
00692     }
00693     return nearHit.distance();
00694 }
00695 
00696 
00697 // Calculate nearest point on/in shapei
00698 Foam::scalar Foam::octreeDataFace::calcNearest
00699 (
00700     const label index,
00701     const linePointRef& ln,
00702     point& linePt,
00703     point& shapePt
00704 ) const
00705 {
00706     notImplemented
00707     (
00708         "octreeDataFace::calcNearest(const label, const linePointRef&"
00709         ", point&, point&)"
00710     );
00711     return GREAT;
00712 }
00713 
00714 
00715 void Foam::octreeDataFace::write(Ostream& os, const label index) const
00716 {
00717     os << meshFaces_[index] << " " << allBb_[index];
00718 }
00719 
00720 
00721 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines