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

octreeDataTriSurface.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 Description
00025 
00026 \*---------------------------------------------------------------------------*/
00027 
00028 #include <meshTools/octreeDataTriSurface.H>
00029 
00030 #include <OpenFOAM/labelList.H>
00031 #include <meshTools/treeBoundBox.H>
00032 #include <OpenFOAM/faceList.H>
00033 #include <OpenFOAM/triPointRef.H>
00034 #include <meshTools/octree.H>
00035 #include <meshTools/triSurfaceTools.H>
00036 #include <meshTools/triangleFuncs.H>
00037 
00038 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00039 
00040 defineTypeNameAndDebug(Foam::octreeDataTriSurface, 0);
00041 
00042 Foam::scalar Foam::octreeDataTriSurface::tol(1E-6);
00043 
00044 
00045 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00046 
00047 // Fast distance to triangle calculation. From
00048 // "Distance Between Point and Trangle in 3D"
00049 // David Eberly, Magic Software Inc. Aug. 2003.
00050 // Works on function Q giving distance to point and tries to minimize this.
00051 void Foam::octreeDataTriSurface::nearestCoords
00052 (
00053     const point& base,
00054     const point& E0,
00055     const point& E1,
00056     const scalar a,
00057     const scalar b,
00058     const scalar c,
00059     const point& P,
00060     scalar& s,
00061     scalar& t
00062 )
00063 {
00064     // distance vector
00065     const vector D(base - P);
00066 
00067     // Precalculate distance factors.
00068     const scalar d = E0 & D;
00069     const scalar e = E1 & D;
00070 
00071     // Do classification
00072     const scalar det = a*c - b*b;
00073 
00074     s = b*e - c*d;
00075     t = b*d - a*e;
00076 
00077     if (s+t < det)
00078     {
00079         if (s < 0)
00080         {
00081             if (t < 0)
00082             {
00083                 //region 4
00084                 if (e > 0)
00085                 {
00086                     //min on edge t = 0
00087                     t = 0;
00088                     s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
00089                 }
00090                 else
00091                 {
00092                     //min on edge s=0
00093                     s = 0;
00094                     t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
00095                 }
00096             }
00097             else
00098             {
00099                 //region 3. Min on edge s = 0
00100                 s = 0;
00101                 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
00102             }
00103         }
00104         else if (t < 0)
00105         {
00106             //region 5
00107             t = 0;
00108             s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
00109         }
00110         else
00111         {
00112             //region 0
00113             const scalar invDet = 1/det;
00114             s *= invDet;
00115             t *= invDet;
00116         }
00117     }
00118     else
00119     {
00120         if (s < 0)
00121         {
00122             //region 2
00123             const scalar tmp0 = b + d;
00124             const scalar tmp1 = c + e;
00125             if (tmp1 > tmp0)
00126             {
00127                 //min on edge s+t=1
00128                 const scalar numer = tmp1 - tmp0;
00129                 const scalar denom = a-2*b+c;
00130                 s = (numer >= denom ? 1 : numer/denom);
00131                 t = 1 - s;
00132             }
00133             else
00134             {
00135                 //min on edge s=0
00136                 s = 0;
00137                 t = (tmp1 <= 0 ? 1 : (e >= 0 ? 0 : - e/c));
00138             }
00139         }
00140         else if (t < 0)
00141         {
00142             //region 6
00143             const scalar tmp0 = b + d;
00144             const scalar tmp1 = c + e;
00145             if (tmp1 > tmp0)
00146             {
00147                 //min on edge s+t=1
00148                 const scalar numer = tmp1 - tmp0;
00149                 const scalar denom = a-2*b+c;
00150                 s = (numer >= denom ? 1 : numer/denom);
00151                 t = 1 - s;
00152             }
00153             else
00154             {
00155                 //min on edge t=0
00156                 t = 0;
00157                 s = (tmp1 <= 0 ? 1 : (d >= 0 ? 0 : - d/a));
00158             }
00159         }
00160         else
00161         {
00162             //region 1
00163             const scalar numer = c+e-(b+d);
00164             if (numer <= 0)
00165             {
00166                 s = 0;
00167             }
00168             else
00169             {
00170                 const scalar denom = a-2*b+c;
00171                 s = (numer >= denom ? 1 : numer/denom);
00172             }
00173         }
00174         t = 1 - s;
00175     }
00176 
00177 
00178     // Calculate distance.
00179     // Note: abs should not be needed but truncation error causes problems
00180     // with points very close to one of the triangle vertices.
00181     // (seen up to -9e-15). Alternatively add some small value.
00182 
00183     // const scalar f = D & D;
00184     // return a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f + SMALL;
00185     // return Foam::mag(a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f);
00186 }
00187 
00188 
00189 Foam::point Foam::octreeDataTriSurface::nearestPoint
00190 (
00191     const label index,
00192     const point& p
00193 ) const
00194 {
00195     scalar s;
00196     scalar t;
00197 
00198     nearestCoords
00199     (
00200         base_[index],
00201         E0_[index],
00202         E1_[index],
00203         a_[index],
00204         b_[index],
00205         c_[index],
00206         p,
00207         s,
00208         t
00209     );
00210 
00211     return base_[index] + s*E0_[index] + t*E1_[index];
00212 }
00213 
00214 
00215 // Helper function to calculate tight fitting bounding boxes.
00216 Foam::treeBoundBoxList Foam::octreeDataTriSurface::calcBb
00217 (
00218     const triSurface& surf
00219 )
00220 {
00221     treeBoundBoxList allBb(surf.size(), treeBoundBox::invertedBox);
00222 
00223     const labelListList& pointFcs = surf.pointFaces();
00224     const pointField& localPts = surf.localPoints();
00225 
00226     forAll(pointFcs, pointI)
00227     {
00228         const labelList& myFaces = pointFcs[pointI];
00229         const point& vertCoord = localPts[pointI];
00230 
00231         forAll(myFaces, myFaceI)
00232         {
00233             // Update bb
00234             label faceI = myFaces[myFaceI];
00235 
00236             treeBoundBox& bb = allBb[faceI];
00237 
00238             bb.min() = min(bb.min(), vertCoord);
00239             bb.max() = max(bb.max(), vertCoord);
00240         }
00241     }
00242 
00243     return allBb;
00244 }
00245 
00246 
00247 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00248 
00249 // Construct from components
00250 Foam::octreeDataTriSurface::octreeDataTriSurface(const triSurface& surface)
00251 :
00252     surface_(surface),
00253     allBb_(calcBb(surface_)),
00254     base_(surface_.size()),
00255     E0_(surface_.size()),
00256     E1_(surface_.size()),
00257     a_(surface_.size()),
00258     b_(surface_.size()),
00259     c_(surface_.size())
00260 {
00261     // Precalculate factors for distance calculation
00262     const pointField& points = surface_.points();
00263 
00264     forAll(surface_, faceI)
00265     {
00266         const labelledTri& f = surface_[faceI];
00267 
00268         // Calculate base and spanning vectors of triangles
00269         base_[faceI] = points[f[1]];
00270         E0_[faceI] = points[f[0]] - points[f[1]];
00271         E1_[faceI] = points[f[2]] - points[f[1]];
00272 
00273         a_[faceI] = E0_[faceI] & E0_[faceI];
00274         b_[faceI] = E0_[faceI] & E1_[faceI];
00275         c_[faceI] = E1_[faceI] & E1_[faceI];
00276     }
00277 }
00278 
00279 
00280 // Construct from components
00281 Foam::octreeDataTriSurface::octreeDataTriSurface
00282 (
00283     const triSurface& surface,
00284     const treeBoundBoxList& allBb
00285 )
00286 :
00287     surface_(surface),
00288     allBb_(allBb),
00289     base_(surface_.size()),
00290     E0_(surface_.size()),
00291     E1_(surface_.size()),
00292     a_(surface_.size()),
00293     b_(surface_.size()),
00294     c_(surface_.size())
00295 {
00296     const pointField& points = surface_.points();
00297 
00298     forAll(surface_, faceI)
00299     {
00300         const labelledTri& f = surface_[faceI];
00301 
00302         // Calculate base and spanning vectors of triangles
00303         base_[faceI] = points[f[1]];
00304         E0_[faceI] = points[f[0]] - points[f[1]];
00305         E1_[faceI] = points[f[2]] - points[f[1]];
00306 
00307         a_[faceI] = E0_[faceI] & E0_[faceI];
00308         b_[faceI] = E0_[faceI] & E1_[faceI];
00309         c_[faceI] = E1_[faceI] & E1_[faceI];
00310     }
00311 }
00312 
00313 
00314 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00315 
00316 Foam::label Foam::octreeDataTriSurface::getSampleType
00317 (
00318     const octree<octreeDataTriSurface>& oc,
00319     const point& sample
00320 ) const
00321 
00322 {
00323     treeBoundBox tightest(treeBoundBox::greatBox);
00324     scalar tightestDist(treeBoundBox::great);
00325 
00326     // Find nearest face to sample
00327     label faceI = oc.findNearest(sample, tightest, tightestDist);
00328 
00329     if (debug & 2)
00330     {
00331         Pout<< "getSampleType : sample:" << sample
00332             << " nearest face:" << faceI;
00333     }
00334 
00335     if (faceI == -1)
00336     {
00337         FatalErrorIn
00338         (
00339             "octreeDataTriSurface::getSampleType"
00340             "(octree<octreeDataTriSurface>&, const point&)"
00341         )   << "Could not find " << sample << " in octree."
00342             << abort(FatalError);
00343     }
00344 
00345     const pointField& pts = surface_.points();
00346     const labelledTri& f = surface_[faceI];
00347 
00348     pointHit curHit = triPointRef
00349     (
00350         pts[f[0]],
00351         pts[f[1]],
00352         pts[f[2]]
00353     ).nearestPoint(sample);
00354 
00355     // Get normal according to position on face. On point -> pointNormal,
00356     // on edge-> edge normal, face normal on interior.
00357     vector n
00358     (
00359         triSurfaceTools::surfaceNormal
00360         (
00361             surface_,
00362             faceI,
00363             curHit.rawPoint()
00364         )
00365     );
00366 
00367     return
00368         octree<octreeDataTriSurface>::getVolType(n, sample - curHit.rawPoint());
00369 }
00370 
00371 
00372 // Check if any point on triangle is inside cubeBb.
00373 bool Foam::octreeDataTriSurface::overlaps
00374 (
00375     const label index,
00376     const treeBoundBox& cubeBb
00377 ) const
00378 {
00379     //return cubeBb.overlaps(allBb_[index]);
00380 
00381     //- Exact test of triangle intersecting bb
00382 
00383     // Quick rejection.
00384     if (!cubeBb.overlaps(allBb_[index]))
00385     {
00386         return false;
00387     }
00388 
00389     // Triangle points
00390     const pointField& points = surface_.points();
00391     const labelledTri& f = surface_[index];
00392     const point& p0 = points[f[0]];
00393     const point& p1 = points[f[1]];
00394     const point& p2 = points[f[2]];
00395 
00396     // Check if one or more triangle point inside
00397     if (cubeBb.contains(p0) || cubeBb.contains(p1) || cubeBb.contains(p2))
00398     {
00399         // One or more points inside
00400         return true;
00401     }
00402 
00403     // Now we have the difficult case: all points are outside but connecting
00404     // edges might go through cube. Use fast intersection of bounding box.
00405 
00406     return triangleFuncs::intersectBb(p0, p1, p2, cubeBb);
00407 }
00408 
00409 
00410 bool Foam::octreeDataTriSurface::contains
00411 (
00412     const label,
00413     const point&
00414 ) const
00415 {
00416     notImplemented
00417     (
00418         "octreeDataTriSurface::contains(const label, const point&)"
00419     );
00420 
00421     return false;
00422 }
00423 
00424 
00425 bool Foam::octreeDataTriSurface::intersects
00426 (
00427     const label index,
00428     const point& start,
00429     const point& end,
00430     point& intersectionPoint
00431 ) const
00432 {
00433     if (mag(surface_.faceNormals()[index]) < VSMALL)
00434     {
00435         return false;
00436     }
00437 
00438     const pointField& points = surface_.points();
00439 
00440     const labelledTri& f = surface_[index];
00441 
00442     triPointRef tri(points[f[0]], points[f[1]], points[f[2]]);
00443 
00444     const vector dir(end - start);
00445 
00446     // Disable picking up intersections behind us.
00447     scalar oldTol = intersection::setPlanarTol(0.0);
00448 
00449     pointHit inter = tri.ray(start, dir, intersection::HALF_RAY);
00450 
00451     intersection::setPlanarTol(oldTol);
00452 
00453     if (inter.hit() && inter.distance() <= mag(dir))
00454     {
00455         // Note: no extra test on whether intersection is in front of us
00456         // since using half_ray AND zero tolerance. (note that tolerance
00457         // is used to look behind us)
00458         intersectionPoint = inter.hitPoint();
00459 
00460         return true;
00461     }
00462     else
00463     {
00464         return false;
00465     }
00466 }
00467 
00468 
00469 bool Foam::octreeDataTriSurface::findTightest
00470 (
00471     const label index,
00472     const point& sample,
00473     treeBoundBox& tightest
00474 ) const
00475 {
00476 
00477     // get nearest and furthest away vertex
00478     point myNear, myFar;
00479     allBb_[index].calcExtremities(sample, myNear, myFar);
00480 
00481     const point dist = myFar - sample;
00482     scalar myFarDist = mag(dist);
00483 
00484     point tightestNear, tightestFar;
00485     tightest.calcExtremities(sample, tightestNear, tightestFar);
00486 
00487     scalar tightestFarDist = mag(tightestFar - sample);
00488 
00489     if (tightestFarDist < myFarDist)
00490     {
00491         // Keep current tightest.
00492         return false;
00493     }
00494     else
00495     {
00496         // Construct bb around sample and myFar
00497         const point dist2(fabs(dist.x()), fabs(dist.y()), fabs(dist.z()));
00498 
00499         tightest.min() = sample - dist2;
00500         tightest.max() = sample + dist2;
00501 
00502         return true;
00503     }
00504 }
00505 
00506 
00507 // Determine numerical value of sign of sample compared to shape at index
00508 Foam::scalar Foam::octreeDataTriSurface::calcSign
00509 (
00510     const label index,
00511     const point& sample,
00512     vector& n
00513 ) const
00514 {
00515     n = surface_.faceNormals()[index];
00516 
00517     const labelledTri& tri = surface_[index];
00518 
00519     // take vector from sample to any point on triangle (we use vertex 0)
00520     vector vec = sample - surface_.points()[tri[0]];
00521 
00522     vec /= mag(vec) + VSMALL;
00523 
00524     return n & vec;
00525 }
00526 
00527 
00528 // Calculate nearest point to sample on/in shapei. !Does not set nearest
00529 Foam::scalar Foam::octreeDataTriSurface::calcNearest
00530 (
00531     const label index,
00532     const point& sample,
00533     point&
00534 ) const
00535 {
00536     return mag(nearestPoint(index, sample) - sample);
00537 }
00538 
00539 
00540 // Calculate nearest point on/in shapei
00541 Foam::scalar Foam::octreeDataTriSurface::calcNearest
00542 (
00543     const label index,
00544     const linePointRef& ln,
00545     point& linePt,
00546     point& shapePt
00547 ) const
00548 {
00549     notImplemented
00550     (
00551         "octreeDataTriSurface::calcNearest"
00552         "(const label, const linePointRef&, point& linePt, point&)"
00553     );
00554     return GREAT;
00555 }
00556 
00557 
00558 void Foam::octreeDataTriSurface::write
00559 (
00560     Ostream& os,
00561     const label index
00562 ) const
00563 {
00564     os << surface_[index] << token::SPACE << allBb_[index];
00565 }
00566 
00567 
00568 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines