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

treeBoundBox.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 "treeBoundBox.H"
00027 #include <OpenFOAM/ListOps.H>
00028 
00029 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00030 
00031 const Foam::scalar Foam::treeBoundBox::great(GREAT);
00032 
00033 const Foam::treeBoundBox Foam::treeBoundBox::greatBox
00034 (
00035     vector(-GREAT, -GREAT, -GREAT),
00036     vector(GREAT, GREAT, GREAT)
00037 );
00038 
00039 
00040 const Foam::treeBoundBox Foam::treeBoundBox::invertedBox
00041 (
00042     vector(GREAT, GREAT, GREAT),
00043     vector(-GREAT, -GREAT, -GREAT)
00044 );
00045 
00046 
00048 const Foam::label facesArray[6][4] =
00049 {
00050     {0, 4, 6, 2}, // left
00051     {1, 3, 7, 5}, // right
00052     {0, 1, 5, 4}, // bottom
00053     {2, 6, 7, 3}, // top
00054     {0, 2, 3, 1}, // back
00055     {4, 5, 7, 6}  // front
00056 };
00058 
00059 
00060 const Foam::faceList Foam::treeBoundBox::faces
00061 (
00062     initListList<face, label, 6, 4>(facesArray)
00063 );
00064 
00065 
00067 const Foam::label edgesArray[12][2] =
00068 {
00069     {0, 1}, // 0
00070     {1, 3},
00071     {2, 3}, // 2
00072     {0, 2},
00073     {4, 5}, // 4
00074     {5, 7},
00075     {6, 7}, // 6
00076     {4, 6},
00077     {0, 4}, // 8
00078     {1, 5},
00079     {3, 7}, // 10
00080     {2, 6}
00081 };
00083 
00084 
00085 const Foam::edgeList Foam::treeBoundBox::edges
00086 (
00087     initListList<edge, label, 12, 2>(edgesArray)
00088 );
00089 
00090 
00091 const Foam::FixedList<Foam::vector, 6> Foam::treeBoundBox::faceNormals
00092 (
00093     calcFaceNormals()
00094 );
00095 
00096 
00097 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00098 
00099 Foam::FixedList<Foam::vector, 6> Foam::treeBoundBox::calcFaceNormals()
00100 {
00101     FixedList<vector, 6> normals;
00102     normals[LEFT]   = vector(-1,  0,  0);
00103     normals[RIGHT]  = vector( 1,  0,  0);
00104     normals[BOTTOM] = vector( 0, -1,  0);
00105     normals[TOP]    = vector( 0,  1,  0);
00106     normals[BACK]   = vector( 0,  0, -1);
00107     normals[FRONT]  = vector( 0,  0,  1);
00108     return normals;
00109 }
00110 
00111 
00112 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00113 
00114 // Construct as the bounding box of the given pointField
00115 Foam::treeBoundBox::treeBoundBox(const UList<point>& points)
00116 :
00117     boundBox()
00118 {
00119     if (points.empty())
00120     {
00121         WarningIn
00122         (
00123             "treeBoundBox::treeBoundBox(const UList<point>&)"
00124         )   << "cannot find bounding box for zero-sized pointField"
00125             << "returning zero" << endl;
00126 
00127         return;
00128     }
00129 
00130     min() = points[0];
00131     max() = points[0];
00132 
00133     for (label i = 1; i < points.size(); i++)
00134     {
00135         min() = ::Foam::min(min(), points[i]);
00136         max() = ::Foam::max(max(), points[i]);
00137     }
00138 }
00139 
00140 
00141 // Construct as the bounding box of the given pointField
00142 Foam::treeBoundBox::treeBoundBox
00143 (
00144     const UList<point>& points,
00145     const UList<label>& meshPoints
00146 )
00147 :
00148     boundBox()
00149 {
00150     if (points.empty() || meshPoints.empty())
00151     {
00152         WarningIn
00153         (
00154             "treeBoundBox::treeBoundBox"
00155             "(const UList<point>&, const UList<label>&)"
00156         )   << "cannot find bounding box for zero-sized pointField"
00157             << "returning zero" << endl;
00158 
00159         return;
00160     }
00161 
00162     min() = points[meshPoints[0]];
00163     max() = points[meshPoints[0]];
00164 
00165     for (label i = 1; i < meshPoints.size(); i++)
00166     {
00167         min() = ::Foam::min(min(), points[meshPoints[i]]);
00168         max() = ::Foam::max(max(), points[meshPoints[i]]);
00169     }
00170 }
00171 
00172 
00173 // Construct from Istream
00174 Foam::treeBoundBox::treeBoundBox(Istream& is)
00175 :
00176     boundBox(is)
00177 {}
00178 
00179 
00180 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00181 
00182 Foam::pointField Foam::treeBoundBox::points() const
00183 {
00184     pointField points(8);
00185     forAll(points, octant)
00186     {
00187         points[octant] = corner(octant);
00188 
00189     }
00190     return points;
00191 }
00192 
00193 
00194 Foam::treeBoundBox Foam::treeBoundBox::subBbox(const direction octant) const
00195 {
00196     return subBbox(midpoint(), octant);
00197 }
00198 
00199 
00200 // Octant to bounding box using permutation only.
00201 Foam::treeBoundBox Foam::treeBoundBox::subBbox
00202 (
00203     const point& mid,
00204     const direction octant
00205 ) const
00206 {
00207     if (octant > 7)
00208     {
00209         FatalErrorIn
00210         (
00211             "treeBoundBox::subBbox(const point&, const direction)"
00212         )   << "octant should be [0..7]"
00213             << abort(FatalError);
00214     }
00215 
00216     // start with a copy of this bounding box and adjust limits accordingly
00217     treeBoundBox subBb(*this);
00218     point& bbMin = subBb.min();
00219     point& bbMax = subBb.max();
00220 
00221     if (octant & treeBoundBox::RIGHTHALF)
00222     {
00223         bbMin.x() = mid.x();    // mid -> max
00224     }
00225     else
00226     {
00227         bbMax.x() = mid.x();    // min -> mid
00228     }
00229 
00230     if (octant & treeBoundBox::TOPHALF)
00231     {
00232         bbMin.y() = mid.y();    // mid -> max
00233     }
00234     else
00235     {
00236         bbMax.y() = mid.y();    // min -> mid
00237     }
00238 
00239     if (octant & treeBoundBox::FRONTHALF)
00240     {
00241         bbMin.z() = mid.z();    // mid -> max
00242     }
00243     else
00244     {
00245         bbMax.z() = mid.z();    // min -> mid
00246     }
00247 
00248     return subBb;
00249 }
00250 
00251 
00252 bool Foam::treeBoundBox::overlaps
00253 (
00254     const point& centre,
00255     const scalar radiusSqr
00256 ) const
00257 {
00258     // Find out where centre is in relation to bb.
00259     // Find nearest point on bb.
00260     scalar distSqr = 0;
00261 
00262     for (direction dir = 0; dir < vector::nComponents; dir++)
00263     {
00264         scalar d0 = min()[dir] - centre[dir];
00265         scalar d1 = max()[dir] - centre[dir];
00266 
00267         if ((d0 > 0) != (d1 > 0))
00268         {
00269             // centre inside both extrema. This component does not add any
00270             // distance.
00271         }
00272         else if (Foam::mag(d0) < Foam::mag(d1))
00273         {
00274             distSqr += d0*d0;
00275         }
00276         else
00277         {
00278             distSqr += d1*d1;
00279         }
00280 
00281         if (distSqr > radiusSqr)
00282         {
00283             return false;
00284         }
00285     }
00286 
00287     return true;
00288 }
00289 
00290 
00291 // line intersection. Returns true if line (start to end) inside
00292 // bb or intersects bb. Sets pt to intersection.
00293 //
00294 // Sutherlands algorithm:
00295 //   loop
00296 //     - start = intersection of line with one of the planes bounding
00297 //       the bounding box
00298 //     - stop if start inside bb (return true)
00299 //     - stop if start and end in same 'half' (e.g. both above bb)
00300 //       (return false)
00301 //
00302 // Uses posBits to efficiently determine 'half' in which start and end
00303 // point are.
00304 //
00305 // Note:
00306 //   - sets coordinate to exact position: e.g. pt.x() = min().x()
00307 //     since plane intersect routine might have truncation error.
00308 //     This makes sure that posBits tests 'inside'
00309 bool Foam::treeBoundBox::intersects
00310 (
00311     const point& overallStart,
00312     const vector& overallVec,
00313     const point& start,
00314     const point& end,
00315     point& pt,
00316     direction& ptOnFaces
00317 ) const
00318 {
00319     const direction endBits = posBits(end);
00320     pt = start;
00321 
00322     while (true)
00323     {
00324         direction ptBits = posBits(pt);
00325 
00326         if (ptBits == 0)
00327         {
00328             // pt inside bb
00329             ptOnFaces = faceBits(pt);
00330             return true;
00331         }
00332 
00333         if ((ptBits & endBits) != 0)
00334         {
00335             // pt and end in same block outside of bb
00336             ptOnFaces = faceBits(pt);
00337             return false;
00338         }
00339 
00340         if (ptBits & LEFTBIT)
00341         {
00342             // Intersect with plane V=min, n=-1,0,0
00343             if (Foam::mag(overallVec.x()) > VSMALL)
00344             {
00345                 scalar s = (min().x() - overallStart.x())/overallVec.x();
00346                 pt.x() = min().x();
00347                 pt.y() = overallStart.y() + overallVec.y()*s;
00348                 pt.z() = overallStart.z() + overallVec.z()*s;
00349             }
00350             else
00351             {
00352                 // Vector not in x-direction. But still intersecting bb planes.
00353                 // So must be close - just snap to bb.
00354                 pt.x() = min().x();
00355             }
00356         }
00357         else if (ptBits & RIGHTBIT)
00358         {
00359             // Intersect with plane V=max, n=1,0,0
00360             if (Foam::mag(overallVec.x()) > VSMALL)
00361             {
00362                 scalar s = (max().x() - overallStart.x())/overallVec.x();
00363                 pt.x() = max().x();
00364                 pt.y() = overallStart.y() + overallVec.y()*s;
00365                 pt.z() = overallStart.z() + overallVec.z()*s;
00366             }
00367             else
00368             {
00369                 pt.x() = max().x();
00370             }
00371         }
00372         else if (ptBits & BOTTOMBIT)
00373         {
00374             // Intersect with plane V=min, n=0,-1,0
00375             if (Foam::mag(overallVec.y()) > VSMALL)
00376             {
00377                 scalar s = (min().y() - overallStart.y())/overallVec.y();
00378                 pt.x() = overallStart.x() + overallVec.x()*s;
00379                 pt.y() = min().y();
00380                 pt.z() = overallStart.z() + overallVec.z()*s;
00381             }
00382             else
00383             {
00384                 pt.x() = min().y();
00385             }
00386         }
00387         else if (ptBits & TOPBIT)
00388         {
00389             // Intersect with plane V=max, n=0,1,0
00390             if (Foam::mag(overallVec.y()) > VSMALL)
00391             {
00392                 scalar s = (max().y() - overallStart.y())/overallVec.y();
00393                 pt.x() = overallStart.x() + overallVec.x()*s;
00394                 pt.y() = max().y();
00395                 pt.z() = overallStart.z() + overallVec.z()*s;
00396             }
00397             else
00398             {
00399                 pt.y() = max().y();
00400             }
00401         }
00402         else if (ptBits & BACKBIT)
00403         {
00404             // Intersect with plane V=min, n=0,0,-1
00405             if (Foam::mag(overallVec.z()) > VSMALL)
00406             {
00407                 scalar s = (min().z() - overallStart.z())/overallVec.z();
00408                 pt.x() = overallStart.x() + overallVec.x()*s;
00409                 pt.y() = overallStart.y() + overallVec.y()*s;
00410                 pt.z() = min().z();
00411             }
00412             else
00413             {
00414                 pt.z() = min().z();
00415             }
00416         }
00417         else if (ptBits & FRONTBIT)
00418         {
00419             // Intersect with plane V=max, n=0,0,1
00420             if (Foam::mag(overallVec.z()) > VSMALL)
00421             {
00422                 scalar s = (max().z() - overallStart.z())/overallVec.z();
00423                 pt.x() = overallStart.x() + overallVec.x()*s;
00424                 pt.y() = overallStart.y() + overallVec.y()*s;
00425                 pt.z() = max().z();
00426             }
00427             else
00428             {
00429                 pt.z() = max().z();
00430             }
00431         }
00432     }
00433 }
00434 
00435 
00436 bool Foam::treeBoundBox::intersects
00437 (
00438     const point& start,
00439     const point& end,
00440     point& pt
00441 ) const
00442 {
00443     direction ptBits;
00444     return intersects(start, end-start, start, end, pt, ptBits);
00445 }
00446 
00447 
00448 // this.bb fully contains bb
00449 bool Foam::treeBoundBox::contains(const treeBoundBox& bb) const
00450 {
00451     return contains(bb.min()) && contains(bb.max());
00452 }
00453 
00454 
00455 bool Foam::treeBoundBox::contains(const vector& dir, const point& pt) const
00456 {
00457     //
00458     // Compare all components against min and max of bb
00459     //
00460     for (direction cmpt=0; cmpt<3; cmpt++)
00461     {
00462         if (pt[cmpt] < min()[cmpt])
00463         {
00464             return false;
00465         }
00466         else if (pt[cmpt] == min()[cmpt])
00467         {
00468             // On edge. Outside if direction points outwards.
00469             if (dir[cmpt] < 0)
00470             {
00471                 return false;
00472             }
00473         }
00474 
00475         if (pt[cmpt] > max()[cmpt])
00476         {
00477             return false;
00478         }
00479         else if (pt[cmpt] == max()[cmpt])
00480         {
00481             // On edge. Outside if direction points outwards.
00482             if (dir[cmpt] > 0)
00483             {
00484                 return false;
00485             }
00486         }
00487     }
00488 
00489     // All components inside bb
00490     return true;
00491 }
00492 
00493 
00494 // Code position of pt on bounding box faces
00495 Foam::direction Foam::treeBoundBox::faceBits(const point& pt) const
00496 {
00497     direction faceBits = 0;
00498     if (pt.x() == min().x())
00499     {
00500         faceBits |= LEFTBIT;
00501     }
00502     else if (pt.x() == max().x())
00503     {
00504         faceBits |= RIGHTBIT;
00505     }
00506 
00507     if (pt.y() == min().y())
00508     {
00509         faceBits |= BOTTOMBIT;
00510     }
00511     else if (pt.y() == max().y())
00512     {
00513         faceBits |= TOPBIT;
00514     }
00515 
00516     if (pt.z() == min().z())
00517     {
00518         faceBits |= BACKBIT;
00519     }
00520     else if (pt.z() == max().z())
00521     {
00522         faceBits |= FRONTBIT;
00523     }
00524     return faceBits;
00525 }
00526 
00527 
00528 // Code position of point relative to box
00529 Foam::direction Foam::treeBoundBox::posBits(const point& pt) const
00530 {
00531     direction posBits = 0;
00532 
00533     if (pt.x() < min().x())
00534     {
00535         posBits |= LEFTBIT;
00536     }
00537     else if (pt.x() > max().x())
00538     {
00539         posBits |= RIGHTBIT;
00540     }
00541 
00542     if (pt.y() < min().y())
00543     {
00544         posBits |= BOTTOMBIT;
00545     }
00546     else if (pt.y() > max().y())
00547     {
00548         posBits |= TOPBIT;
00549     }
00550 
00551     if (pt.z() < min().z())
00552     {
00553         posBits |= BACKBIT;
00554     }
00555     else if (pt.z() > max().z())
00556     {
00557         posBits |= FRONTBIT;
00558     }
00559     return posBits;
00560 }
00561 
00562 
00563 // nearest and furthest corner coordinate.
00564 // !names of treeBoundBox::min() and treeBoundBox::max() are confusing!
00565 void Foam::treeBoundBox::calcExtremities
00566 (
00567     const point& pt,
00568     point& nearest,
00569     point& furthest
00570 ) const
00571 {
00572     scalar nearX, nearY, nearZ;
00573     scalar farX, farY, farZ;
00574 
00575     if (Foam::mag(min().x() - pt.x()) < Foam::mag(max().x() - pt.x()))
00576     {
00577         nearX = min().x();
00578         farX = max().x();
00579     }
00580     else
00581     {
00582         nearX = max().x();
00583         farX = min().x();
00584     }
00585 
00586     if (Foam::mag(min().y() - pt.y()) < Foam::mag(max().y() - pt.y()))
00587     {
00588         nearY = min().y();
00589         farY = max().y();
00590     }
00591     else
00592     {
00593         nearY = max().y();
00594         farY = min().y();
00595     }
00596 
00597     if (Foam::mag(min().z() - pt.z()) < Foam::mag(max().z() - pt.z()))
00598     {
00599         nearZ = min().z();
00600         farZ = max().z();
00601     }
00602     else
00603     {
00604         nearZ = max().z();
00605         farZ = min().z();
00606     }
00607 
00608     nearest = point(nearX, nearY, nearZ);
00609     furthest = point(farX, farY, farZ);
00610 }
00611 
00612 
00613 Foam::scalar Foam::treeBoundBox::maxDist(const point& pt) const
00614 {
00615     point near, far;
00616     calcExtremities(pt, near, far);
00617 
00618     return Foam::mag(far - pt);
00619 }
00620 
00621 
00622 // Distance comparator
00623 // Compare all vertices of bounding box against all of other bounding
00624 // box to see if all vertices of one are nearer
00625 Foam::label Foam::treeBoundBox::distanceCmp
00626 (
00627     const point& pt,
00628     const treeBoundBox& other
00629 ) const
00630 {
00631     //
00632     // Distance point <-> nearest and furthest away vertex of this
00633     //
00634 
00635     point nearThis, farThis;
00636 
00637     // get nearest and furthest away vertex
00638     calcExtremities(pt, nearThis, farThis);
00639 
00640     const scalar minDistThis =
00641         sqr(nearThis.x() - pt.x())
00642      +  sqr(nearThis.y() - pt.y())
00643      +  sqr(nearThis.z() - pt.z());
00644     const scalar maxDistThis =
00645         sqr(farThis.x() - pt.x())
00646      +  sqr(farThis.y() - pt.y())
00647      +  sqr(farThis.z() - pt.z());
00648 
00649     //
00650     // Distance point <-> other
00651     //
00652 
00653     point nearOther, farOther;
00654 
00655     // get nearest and furthest away vertex
00656     other.calcExtremities(pt, nearOther, farOther);
00657 
00658     const scalar minDistOther =
00659         sqr(nearOther.x() - pt.x())
00660      +  sqr(nearOther.y() - pt.y())
00661      +  sqr(nearOther.z() - pt.z());
00662     const scalar maxDistOther =
00663         sqr(farOther.x() - pt.x())
00664      +  sqr(farOther.y() - pt.y())
00665      +  sqr(farOther.z() - pt.z());
00666 
00667     //
00668     // Categorize
00669     //
00670     if (maxDistThis < minDistOther)
00671     {
00672         // All vertices of this are nearer to point than any vertex of other
00673         return -1;
00674     }
00675     else if (minDistThis > maxDistOther)
00676     {
00677         // All vertices of this are further from point than any vertex of other
00678         return 1;
00679     }
00680     else
00681     {
00682         // Mixed bag
00683         return 0;
00684     }
00685 }
00686 
00687 
00688 // * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
00689 
00690 bool Foam::operator==(const treeBoundBox& a, const treeBoundBox& b)
00691 {
00692     return operator==
00693     (
00694         static_cast<const boundBox&>(a),
00695         static_cast<const boundBox&>(b)
00696     );
00697 }
00698 
00699 
00700 bool Foam::operator!=(const treeBoundBox& a, const treeBoundBox& b)
00701 {
00702     return !(a == b);
00703 }
00704 
00705 
00706 // * * * * * * * * * * * * * * * Ostream Operator  * * * * * * * * * * * * * //
00707 
00708 Foam::Ostream& Foam::operator<<(Ostream& os, const treeBoundBox& bb)
00709 {
00710     return os << static_cast<const boundBox&>(bb);
00711 }
00712 
00713 
00714 Foam::Istream& Foam::operator>>(Istream& is, treeBoundBox& bb)
00715 {
00716     return is >> static_cast<boundBox&>(bb);
00717 }
00718 
00719 
00720 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines