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

treeDataTriSurface.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 "treeDataTriSurface.H"
00027 #include <meshTools/triSurfaceTools.H>
00028 #include <meshTools/triangleFuncs.H>
00029 #include "indexedOctree.H"
00030 
00031 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00032 
00033 defineTypeNameAndDebug(Foam::treeDataTriSurface, 0);
00034 
00035 
00036 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00037 
00038 // Fast distance to triangle calculation. From
00039 // "Distance Between Point and Trangle in 3D"
00040 // David Eberly, Magic Software Inc. Aug. 2003.
00041 // Works on function Q giving distance to point and tries to minimize this.
00042 Foam::scalar Foam::treeDataTriSurface::nearestCoords
00043 (
00044     const point& base,
00045     const point& E0,
00046     const point& E1,
00047     const scalar a,
00048     const scalar b,
00049     const scalar c,
00050     const point& P,
00051     scalar& s,
00052     scalar& t
00053 )
00054 {
00055     // distance vector
00056     const vector D(base - P);
00057 
00058     // Precalculate distance factors.
00059     const scalar d = E0 & D;
00060     const scalar e = E1 & D;
00061 
00062     // Do classification
00063     const scalar det = a*c - b*b;
00064 
00065     s = b*e - c*d;
00066     t = b*d - a*e;
00067 
00068     if (s+t < det)
00069     {
00070         if (s < 0)
00071         {
00072             if (t < 0)
00073             {
00074                 //region 4
00075                 if (e > 0)
00076                 {
00077                     //min on edge t = 0
00078                     t = 0;
00079                     s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
00080                 }
00081                 else
00082                 {
00083                     //min on edge s=0
00084                     s = 0;
00085                     t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
00086                 }
00087             }
00088             else
00089             {
00090                 //region 3. Min on edge s = 0
00091                 s = 0;
00092                 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
00093             }
00094         }
00095         else if (t < 0)
00096         {
00097             //region 5
00098             t = 0;
00099             s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
00100         }
00101         else
00102         {
00103             //region 0
00104             const scalar invDet = 1/det;
00105             s *= invDet;
00106             t *= invDet;
00107         }
00108     }
00109     else
00110     {
00111         if (s < 0)
00112         {
00113             //region 2
00114             const scalar tmp0 = b + d;
00115             const scalar tmp1 = c + e;
00116             if (tmp1 > tmp0)
00117             {
00118                 //min on edge s+t=1
00119                 const scalar numer = tmp1 - tmp0;
00120                 const scalar denom = a-2*b+c;
00121                 s = (numer >= denom ? 1 : numer/denom);
00122                 t = 1 - s;
00123             }
00124             else
00125             {
00126                 //min on edge s=0
00127                 s = 0;
00128                 t = (tmp1 <= 0 ? 1 : (e >= 0 ? 0 : - e/c));
00129             }
00130         }
00131         else if (t < 0)
00132         {
00133             //region 6
00134             const scalar tmp0 = b + d;
00135             const scalar tmp1 = c + e;
00136             if (tmp1 > tmp0)
00137             {
00138                 //min on edge s+t=1
00139                 const scalar numer = tmp1 - tmp0;
00140                 const scalar denom = a-2*b+c;
00141                 s = (numer >= denom ? 1 : numer/denom);
00142                 t = 1 - s;
00143             }
00144             else
00145             {
00146                 //min on edge t=0
00147                 t = 0;
00148                 s = (tmp1 <= 0 ? 1 : (d >= 0 ? 0 : - d/a));
00149             }
00150         }
00151         else
00152         {
00153             //region 1
00154             const scalar numer = c+e-(b+d);
00155             if (numer <= 0)
00156             {
00157                 s = 0;
00158             }
00159             else
00160             {
00161                 const scalar denom = a-2*b+c;
00162                 s = (numer >= denom ? 1 : numer/denom);
00163             }
00164         }
00165         t = 1 - s;
00166     }
00167 
00168 
00169     // Calculate distance.
00170     // Note: abs should not be needed but truncation error causes problems
00171     // with points very close to one of the triangle vertices.
00172     // (seen up to -9e-15). Alternatively add some small value.
00173 
00174     const scalar f = D & D;
00175     return Foam::mag(a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f);
00176 }
00177 
00178 
00179 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00180 
00181 // Construct from components
00182 Foam::treeDataTriSurface::treeDataTriSurface(const triSurface& surface)
00183 :
00184     surface_(surface)
00185 {}
00186 
00187 
00188 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00189 
00190 Foam::pointField Foam::treeDataTriSurface::points() const
00191 {
00192     const pointField& points = surface_.points();
00193 
00194     pointField centres(surface_.size());
00195 
00196     forAll(surface_, triI)
00197     {
00198         centres[triI] = surface_[triI].centre(points);
00199     }
00200     return centres;
00201 }
00202 
00203 
00204 //- Get type of sample (inside/outside/mixed) w.r.t. surface.
00205 Foam::label Foam::treeDataTriSurface::getVolumeType
00206 (
00207     const indexedOctree<treeDataTriSurface>& tree,
00208     const point& sample
00209 ) const
00210 {
00211     // Find nearest point
00212     const treeBoundBox& treeBb = tree.bb();
00213 
00214     pointIndexHit pHit = tree.findNearest
00215     (
00216         sample,
00217         max
00218         (
00219             Foam::sqr(GREAT),
00220             Foam::magSqr(treeBb.span())
00221         )
00222     );
00223 
00224     if (!pHit.hit())
00225     {
00226         FatalErrorIn("treeDataTriSurface::getVolumeType(..)")
00227             << "treeBb:" << treeBb
00228             << " sample:" << sample
00229             << " pHit:" << pHit
00230             << abort(FatalError);
00231     }
00232 
00233     triSurfaceTools::sideType t = triSurfaceTools::surfaceSide
00234     (
00235         surface_,
00236         sample,
00237         pHit.index(),
00238         pHit.hitPoint(),
00239         indexedOctree<treeDataTriSurface>::perturbTol()
00240     );
00241 
00242     if (t == triSurfaceTools::UNKNOWN)
00243     {
00244         return indexedOctree<treeDataTriSurface>::UNKNOWN;
00245     }
00246     else if (t == triSurfaceTools::INSIDE)
00247     {
00248         return indexedOctree<treeDataTriSurface>::INSIDE;
00249     }
00250     else if (t == triSurfaceTools::OUTSIDE)
00251     {
00252         return indexedOctree<treeDataTriSurface>::OUTSIDE;
00253     }
00254     else
00255     {
00256         FatalErrorIn("treeDataTriSurface::getVolumeType(..)")
00257             << "problem" << abort(FatalError);
00258         return indexedOctree<treeDataTriSurface>::UNKNOWN;
00259     }
00260 }
00261 
00262 
00263 // Check if any point on triangle is inside cubeBb.
00264 bool Foam::treeDataTriSurface::overlaps
00265 (
00266     const label index,
00267     const treeBoundBox& cubeBb
00268 ) const
00269 {
00270     const pointField& points = surface_.points();
00271     const labelledTri& f = surface_[index];
00272 
00273     // Triangle points
00274     const point& p0 = points[f[0]];
00275     const point& p1 = points[f[1]];
00276     const point& p2 = points[f[2]];
00277 
00278     treeBoundBox triBb(p0, p0);
00279     triBb.min() = min(triBb.min(), p1);
00280     triBb.min() = min(triBb.min(), p2);
00281 
00282     triBb.max() = max(triBb.max(), p1);
00283     triBb.max() = max(triBb.max(), p2);
00284 
00285     //- For testing: robust one
00286     //return cubeBb.overlaps(triBb);
00287 
00288     //- Exact test of triangle intersecting bb
00289 
00290     // Quick rejection. If whole bounding box of tri is outside cubeBb then
00291     // there will be no intersection.
00292     if (!cubeBb.overlaps(triBb))
00293     {
00294         return false;
00295     }
00296 
00297     // Check if one or more triangle point inside
00298     if (cubeBb.contains(p0) || cubeBb.contains(p1) || cubeBb.contains(p2))
00299     {
00300         // One or more points inside
00301         return true;
00302     }
00303 
00304     // Now we have the difficult case: all points are outside but connecting
00305     // edges might go through cube. Use fast intersection of bounding box.
00306 
00307     //return triangleFuncs::intersectBbExact(p0, p1, p2, cubeBb);
00308     return triangleFuncs::intersectBb(p0, p1, p2, cubeBb);
00309 }
00310 
00311 
00312 // Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
00313 // nearestPoint.
00314 void Foam::treeDataTriSurface::findNearest
00315 (
00316     const labelList& indices,
00317     const point& sample,
00318 
00319     scalar& nearestDistSqr,
00320     label& minIndex,
00321     point& nearestPoint
00322 ) const
00323 {
00324     const pointField& points = surface_.points();
00325 
00326     forAll(indices, i)
00327     {
00328         label index = indices[i];
00329         const labelledTri& f = surface_[index];
00330 
00331         // Triangle points
00332         const point& p0 = points[f[0]];
00333         const point& p1 = points[f[1]];
00334         const point& p2 = points[f[2]];
00335 
00336 
00340         //
00342         //point triBbMin = min(p0, min(p1, p2));
00343         //point triBbMax = max(p0, max(p1, p2));
00344         //
00345         //if
00346         //(
00347         //    indexedOctree<treeDataTriSurface>::intersects
00348         //    (
00349         //        triBbMin,
00350         //        triBbMax,
00351         //        nearestDistSqr,
00352         //        sample
00353         //    )
00354         //)
00355         {
00356             // Get spanning vectors of triangle
00357             vector base(p1);
00358             vector E0(p0 - p1);
00359             vector E1(p2 - p1);
00360 
00361             scalar a(E0& E0);
00362             scalar b(E0& E1);
00363             scalar c(E1& E1);
00364 
00365             // Get nearest point in s,t coordinates (s is along E0, t is along
00366             // E1)
00367             scalar s;
00368             scalar t;
00369 
00370             scalar distSqr = nearestCoords
00371             (
00372                 base,
00373                 E0,
00374                 E1,
00375                 a,
00376                 b,
00377                 c,
00378                 sample,
00379 
00380                 s,
00381                 t
00382             );
00383 
00384             if (distSqr < nearestDistSqr)
00385             {
00386                 nearestDistSqr = distSqr;
00387                 minIndex = index;
00388                 nearestPoint = base + s*E0 + t*E1;
00389             }
00390         }
00391     }
00392 }
00393 
00394 
00395 // Calculate nearest point to line. Updates (if any) nearestDistSqr, minIndex,
00396 // nearestPoint.
00397 void Foam::treeDataTriSurface::findNearest
00398 (
00399     const labelList& indices,
00400     const linePointRef& ln,
00401 
00402     treeBoundBox& tightest,
00403     label& minIndex,
00404     point& linePoint,
00405     point& nearestPoint
00406 ) const
00407 {
00408     notImplemented
00409     (
00410         "treeDataTriSurface::findNearest(const labelList&"
00411         ", const linePointRef&, treeBoundBox&, label&, point&, point&) const"
00412     );
00413 }
00414 
00415 
00416 bool Foam::treeDataTriSurface::intersects
00417 (
00418     const label index,
00419     const point& start,
00420     const point& end,
00421     point& intersectionPoint
00422 ) const
00423 {
00424     const pointField& points = surface_.points();
00425 
00426     const labelledTri& f = surface_[index];
00427 
00428     // Do quick rejection test
00429     treeBoundBox triBb(points[f[0]], points[f[0]]);
00430     triBb.min() = min(triBb.min(), points[f[1]]);
00431     triBb.max() = max(triBb.max(), points[f[1]]);
00432     triBb.min() = min(triBb.min(), points[f[2]]);
00433     triBb.max() = max(triBb.max(), points[f[2]]);
00434 
00435     const direction startBits(triBb.posBits(start));
00436     const direction endBits(triBb.posBits(end));
00437 
00438     if ((startBits & endBits) != 0)
00439     {
00440         // start and end in same block outside of triBb.
00441         return false;
00442     }
00443 
00444     const triPointRef tri(points[f[0]], points[f[1]], points[f[2]]);
00445 
00446     const vector dir(end - start);
00447 
00448     // Use relative tolerance (from octree) to determine intersection.
00449 
00450     pointHit inter = tri.intersection
00451     (
00452         start,
00453         dir,
00454         intersection::HALF_RAY,
00455         indexedOctree<treeDataTriSurface>::perturbTol()
00456     );
00457 
00458     if (inter.hit() && inter.distance() <= 1)
00459     {
00460         // Note: no extra test on whether intersection is in front of us
00461         // since using half_ray.
00462         intersectionPoint = inter.hitPoint();
00463 
00464         return true;
00465     }
00466     else
00467     {
00468         return false;
00469     }
00470 
00471 
00472     //- Using exact intersections
00473     //pointHit info = f.tri(points).intersectionExact(start, end);
00474     //
00475     //if (info.hit())
00476     //{
00477     //    intersectionPoint = info.hitPoint();
00478     //}
00479     //return info.hit();
00480 }
00481 
00482 
00483 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines