00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 #include "triSurfaceMesh.H"
00027 #include <OpenFOAM/Random.H>
00028 #include <OpenFOAM/addToRunTimeSelectionTable.H>
00029 #include <OpenFOAM/EdgeMap.H>
00030 #include <triSurface/triSurfaceFields.H>
00031 #include <OpenFOAM/Time.H>
00032 #include <OpenFOAM/PackedBoolList.H>
00033 
00034 
00035 
00036 namespace Foam
00037 {
00038 
00039 defineTypeNameAndDebug(triSurfaceMesh, 0);
00040 addToRunTimeSelectionTable(searchableSurface, triSurfaceMesh, dict);
00041 
00042 }
00043 
00044 
00045 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 
00094 
00095 
00096 
00097 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 const Foam::fileName& Foam::triSurfaceMesh::checkFile
00106 (
00107     const fileName& fName,
00108     const fileName& objectName
00109 )
00110 {
00111     if (fName.empty())
00112     {
00113         FatalErrorIn
00114         (
00115             "triSurfaceMesh::checkFile(const fileName&, const fileName&)"
00116         )   << "Cannot find triSurfaceMesh starting from "
00117             << objectName << exit(FatalError);
00118     }
00119     return fName;
00120 }
00121 
00122 
00123 bool Foam::triSurfaceMesh::addFaceToEdge
00124 (
00125     const edge& e,
00126     EdgeMap<label>& facesPerEdge
00127 )
00128 {
00129     EdgeMap<label>::iterator eFnd = facesPerEdge.find(e);
00130     if (eFnd != facesPerEdge.end())
00131     {
00132         if (eFnd() == 2)
00133         {
00134             return false;
00135         }
00136         eFnd()++;
00137     }
00138     else
00139     {
00140         facesPerEdge.insert(e, 1);
00141     }
00142     return true;
00143 }
00144 
00145 
00146 bool Foam::triSurfaceMesh::isSurfaceClosed() const
00147 {
00148     
00149     
00150     labelListList pointFaces;
00151     invertManyToMany(points().size(), *this, pointFaces);
00152 
00153     
00154     
00155     
00156     
00157     EdgeMap<label> facesPerEdge(100);
00158     forAll(pointFaces, pointI)
00159     {
00160         const labelList& pFaces = pointFaces[pointI];
00161 
00162         facesPerEdge.clear();
00163         forAll(pFaces, i)
00164         {
00165             const labelledTri& f = triSurface::operator[](pFaces[i]);
00166             label fp = findIndex(f, pointI);
00167 
00168             
00169             
00170             
00171 
00172 
00173             
00174             label nextPointI = f[f.fcIndex(fp)];
00175 
00176             if (nextPointI > pointI)
00177             {
00178                 bool okFace = addFaceToEdge
00179                 (
00180                     edge(pointI, nextPointI),
00181                     facesPerEdge
00182                 );
00183 
00184                 if (!okFace)
00185                 {
00186                     return false;
00187                 }
00188             }
00189             
00190             label prevPointI = f[f.rcIndex(fp)];
00191 
00192             if (prevPointI > pointI)
00193             {
00194                 bool okFace = addFaceToEdge
00195                 (
00196                     edge(pointI, prevPointI),
00197                     facesPerEdge
00198                 );
00199 
00200                 if (!okFace)
00201                 {
00202                     return false;
00203                 }
00204             }
00205         }
00206 
00207         
00208         forAllConstIter(EdgeMap<label>, facesPerEdge, iter)
00209         {
00210             if (iter() != 2)
00211             {
00212                 return false;
00213             }
00214         }
00215     }
00216 
00217     return true;
00218 }
00219 
00220 
00221 
00222 
00223 void Foam::triSurfaceMesh::getNextIntersections
00224 (
00225     const indexedOctree<treeDataTriSurface>& octree,
00226     const point& start,
00227     const point& end,
00228     const vector& smallVec,
00229     DynamicList<pointIndexHit, 1, 1>& hits
00230 )
00231 {
00232     const vector dirVec(end-start);
00233     const scalar magSqrDirVec(magSqr(dirVec));
00234 
00235     
00236     vector perturbVec(smallVec);
00237 
00238     while (true)
00239     {
00240         
00241         point pt = hits[hits.size()-1].hitPoint() + perturbVec;
00242 
00243         if (((pt-start)&dirVec) > magSqrDirVec)
00244         {
00245             return;
00246         }
00247 
00248         
00249         pointIndexHit inter = octree.findLine(pt, end);
00250 
00251         if (!inter.hit())
00252         {
00253             return;
00254         }
00255 
00256         
00257         bool duplicateHit = false;
00258         forAllReverse(hits, i)
00259         {
00260             if (hits[i].index() == inter.index())
00261             {
00262                 duplicateHit = true;
00263                 break;
00264             }
00265         }
00266 
00267 
00268         if (duplicateHit)
00269         {
00270             
00271             perturbVec *= 2;
00272         }
00273         else
00274         {
00275             
00276             hits.append(inter);
00277             
00278             perturbVec = smallVec;
00279         }
00280     }
00281 }
00282 
00283 
00284 void Foam::triSurfaceMesh::calcBounds(boundBox& bb, label& nPoints) const
00285 {
00286     
00287     
00288 
00289     const triSurface& s = static_cast<const triSurface&>(*this);
00290 
00291     PackedBoolList pointIsUsed(points().size());
00292 
00293     nPoints = 0;
00294     bb = boundBox::invertedBox;
00295 
00296     forAll(s, triI)
00297     {
00298         const labelledTri& f = s[triI];
00299 
00300         forAll(f, fp)
00301         {
00302             label pointI = f[fp];
00303             if (pointIsUsed.set(pointI, 1u))
00304             {
00305                 bb.min() = ::Foam::min(bb.min(), points()[pointI]);
00306                 bb.max() = ::Foam::max(bb.max(), points()[pointI]);
00307                 nPoints++;
00308             }
00309         }
00310     }
00311 }
00312 
00313 
00314 
00315 
00316 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s)
00317 :
00318     searchableSurface(io),
00319     objectRegistry
00320     (
00321         IOobject
00322         (
00323             io.name(),
00324             io.instance(),
00325             io.local(),
00326             io.db(),
00327             io.readOpt(),
00328             io.writeOpt(),
00329             false       
00330         )
00331     ),
00332     triSurface(s),
00333     tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
00334     maxTreeDepth_(10),
00335     surfaceClosed_(-1)
00336 {}
00337 
00338 
00339 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io)
00340 :
00341     
00342     searchableSurface(io),
00343     
00344     
00345     
00346     
00347     
00348     
00349     
00350     
00351     
00352     
00353     
00354     
00355     
00356     objectRegistry
00357     (
00358         IOobject
00359         (
00360             io.name(),
00361             static_cast<const searchableSurface&>(*this).instance(),
00362             io.local(),
00363             io.db(),
00364             io.readOpt(),
00365             io.writeOpt(),
00366             false       
00367         )
00368     ),
00369     triSurface
00370     (
00371         checkFile
00372         (
00373             searchableSurface::filePath(),
00374             searchableSurface::objectPath()
00375         )
00376     ),
00377     tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
00378     maxTreeDepth_(10),
00379     surfaceClosed_(-1)
00380 {}
00381 
00382 
00383 Foam::triSurfaceMesh::triSurfaceMesh
00384 (
00385     const IOobject& io,
00386     const dictionary& dict
00387 )
00388 :
00389     searchableSurface(io),
00390     
00391     
00392     
00393     
00394     
00395     
00396     
00397     
00398     
00399     
00400     
00401     
00402     
00403     objectRegistry
00404     (
00405         IOobject
00406         (
00407             io.name(),
00408             static_cast<const searchableSurface&>(*this).instance(),
00409             io.local(),
00410             io.db(),
00411             io.readOpt(),
00412             io.writeOpt(),
00413             false       
00414         )
00415     ),
00416     triSurface
00417     (
00418         checkFile
00419         (
00420             searchableSurface::filePath(),
00421             searchableSurface::objectPath()
00422         )
00423     ),
00424     tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
00425     maxTreeDepth_(10),
00426     surfaceClosed_(-1)
00427 {
00428     scalar scaleFactor = 0;
00429 
00430     
00431     
00432     if (dict.readIfPresent("scale", scaleFactor) && scaleFactor > 0)
00433     {
00434         Info<< searchableSurface::name() << " : using scale " << scaleFactor
00435             << endl;
00436         triSurface::scalePoints(scaleFactor);
00437     }
00438 
00439 
00440     
00441     if (dict.readIfPresent("tolerance", tolerance_) && tolerance_ > 0)
00442     {
00443         Info<< searchableSurface::name() << " : using intersection tolerance "
00444             << tolerance_ << endl;
00445     }
00446 
00447 
00448     
00449     if (dict.readIfPresent("maxTreeDepth", maxTreeDepth_) && maxTreeDepth_ > 0)
00450     {
00451         Info<< searchableSurface::name() << " : using maximum tree depth "
00452             << maxTreeDepth_ << endl;
00453     }
00454 }
00455 
00456 
00457 
00458 
00459 Foam::triSurfaceMesh::~triSurfaceMesh()
00460 {
00461     clearOut();
00462 }
00463 
00464 
00465 void Foam::triSurfaceMesh::clearOut()
00466 {
00467     tree_.clear();
00468     edgeTree_.clear();
00469     triSurface::clearOut();
00470 }
00471 
00472 
00473 
00474 
00475 Foam::pointField Foam::triSurfaceMesh::coordinates() const
00476 {
00477     
00478     return PrimitivePatch<labelledTri, SubList, const pointField&>
00479     (
00480         SubList<labelledTri>(*this, triSurface::size()),
00481         triSurface::points()
00482     ).faceCentres();
00483 }
00484 
00485 
00486 void Foam::triSurfaceMesh::movePoints(const pointField& newPoints)
00487 {
00488     tree_.clear();
00489     edgeTree_.clear();
00490     triSurface::movePoints(newPoints);
00491 }
00492 
00493 
00494 const Foam::indexedOctree<Foam::treeDataTriSurface>&
00495     Foam::triSurfaceMesh::tree() const
00496 {
00497     if (tree_.empty())
00498     {
00499         
00500         treeBoundBox bb;
00501         label nPoints;
00502         calcBounds(bb, nPoints);
00503 
00504         if (nPoints != points().size())
00505         {
00506             WarningIn("triSurfaceMesh::tree() const")
00507                 << "Surface " << searchableSurface::name()
00508                 << " does not have compact point numbering."
00509                 << " Of " << points().size() << " only " << nPoints
00510                 << " are used. This might give problems in some routines."
00511                 << endl;
00512         }
00513 
00514 
00515         
00516         Random rndGen(65431);
00517 
00518         
00519         
00520         bb = bb.extend(rndGen, 1E-4);
00521         bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00522         bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00523 
00524         scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00525         indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00526 
00527         tree_.reset
00528         (
00529             new indexedOctree<treeDataTriSurface>
00530             (
00531                 treeDataTriSurface(*this),
00532                 bb,
00533                 maxTreeDepth_,  
00534                 10,             
00535                 3.0             
00536             )
00537         );
00538 
00539         indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00540     }
00541 
00542     return tree_();
00543 }
00544 
00545 
00546 const Foam::indexedOctree<Foam::treeDataEdge>&
00547  Foam::triSurfaceMesh::edgeTree() const
00548 {
00549     if (edgeTree_.empty())
00550     {
00551         
00552         labelList bEdges
00553         (
00554             identity
00555             (
00556                 nEdges()
00557                -nInternalEdges()
00558             )
00559           + nInternalEdges()
00560         );
00561 
00562         treeBoundBox bb;
00563         label nPoints;
00564         calcBounds(bb, nPoints);
00565 
00566         
00567         Random rndGen(65431);
00568 
00569         
00570         
00571 
00572         bb = bb.extend(rndGen, 1E-4);
00573         bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00574         bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00575 
00576         edgeTree_.reset
00577         (
00578             new indexedOctree<treeDataEdge>
00579             (
00580                 treeDataEdge
00581                 (
00582                     false,          
00583                     edges(),        
00584                     localPoints(),  
00585                     bEdges          
00586                 ),
00587                 bb,                 
00588                 maxTreeDepth_,      
00589                 10,                 
00590                 3.0                 
00591             )
00592         );
00593     }
00594     return edgeTree_();
00595 }
00596 
00597 
00598 const Foam::wordList& Foam::triSurfaceMesh::regions() const
00599 {
00600     if (regions_.empty())
00601     {
00602         regions_.setSize(patches().size());
00603         forAll(regions_, regionI)
00604         {
00605             regions_[regionI] = patches()[regionI].name();
00606         }
00607     }
00608     return regions_;
00609 }
00610 
00611 
00612 
00613 bool Foam::triSurfaceMesh::hasVolumeType() const
00614 {
00615     if (surfaceClosed_ == -1)
00616     {
00617         if (isSurfaceClosed())
00618         {
00619             surfaceClosed_ = 1;
00620         }
00621         else
00622         {
00623             surfaceClosed_ = 0;
00624         }
00625     }
00626 
00627     return surfaceClosed_ == 1;
00628 }
00629 
00630 
00631 void Foam::triSurfaceMesh::findNearest
00632 (
00633     const pointField& samples,
00634     const scalarField& nearestDistSqr,
00635     List<pointIndexHit>& info
00636 ) const
00637 {
00638     const indexedOctree<treeDataTriSurface>& octree = tree();
00639 
00640     info.setSize(samples.size());
00641 
00642     scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00643     indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00644 
00645     forAll(samples, i)
00646     {
00647         static_cast<pointIndexHit&>(info[i]) = octree.findNearest
00648         (
00649             samples[i],
00650             nearestDistSqr[i]
00651         );
00652     }
00653 
00654     indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00655 }
00656 
00657 
00658 void Foam::triSurfaceMesh::findLine
00659 (
00660     const pointField& start,
00661     const pointField& end,
00662     List<pointIndexHit>& info
00663 ) const
00664 {
00665     const indexedOctree<treeDataTriSurface>& octree = tree();
00666 
00667     info.setSize(start.size());
00668 
00669     scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00670     indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00671 
00672     forAll(start, i)
00673     {
00674         static_cast<pointIndexHit&>(info[i]) = octree.findLine
00675         (
00676             start[i],
00677             end[i]
00678         );
00679     }
00680 
00681     indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00682 }
00683 
00684 
00685 void Foam::triSurfaceMesh::findLineAny
00686 (
00687     const pointField& start,
00688     const pointField& end,
00689     List<pointIndexHit>& info
00690 ) const
00691 {
00692     const indexedOctree<treeDataTriSurface>& octree = tree();
00693 
00694     info.setSize(start.size());
00695 
00696     scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00697     indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00698 
00699     forAll(start, i)
00700     {
00701         static_cast<pointIndexHit&>(info[i]) = octree.findLineAny
00702         (
00703             start[i],
00704             end[i]
00705         );
00706     }
00707 
00708     indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00709 }
00710 
00711 
00712 void Foam::triSurfaceMesh::findLineAll
00713 (
00714     const pointField& start,
00715     const pointField& end,
00716     List<List<pointIndexHit> >& info
00717 ) const
00718 {
00719     const indexedOctree<treeDataTriSurface>& octree = tree();
00720 
00721     info.setSize(start.size());
00722 
00723     scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00724     indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00725 
00726     
00727     DynamicList<pointIndexHit, 1, 1> hits;
00728 
00729     
00730     
00731     
00732     
00733     
00734     
00735     const vectorField dirVec(end-start);
00736     const scalarField magSqrDirVec(magSqr(dirVec));
00737     const vectorField smallVec
00738     (
00739         indexedOctree<treeDataTriSurface>::perturbTol()*dirVec
00740       + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
00741     );
00742 
00743     forAll(start, pointI)
00744     {
00745         
00746         pointIndexHit inter = octree.findLine(start[pointI], end[pointI]);
00747 
00748         if (inter.hit())
00749         {
00750             hits.clear();
00751             hits.append(inter);
00752 
00753             getNextIntersections
00754             (
00755                 octree,
00756                 start[pointI],
00757                 end[pointI],
00758                 smallVec[pointI],
00759                 hits
00760             );
00761 
00762             info[pointI].transfer(hits);
00763         }
00764         else
00765         {
00766             info[pointI].clear();
00767         }
00768     }
00769 
00770     indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00771 }
00772 
00773 
00774 void Foam::triSurfaceMesh::getRegion
00775 (
00776     const List<pointIndexHit>& info,
00777     labelList& region
00778 ) const
00779 {
00780     region.setSize(info.size());
00781     forAll(info, i)
00782     {
00783         if (info[i].hit())
00784         {
00785             region[i] = triSurface::operator[](info[i].index()).region();
00786         }
00787         else
00788         {
00789             region[i] = -1;
00790         }
00791     }
00792 }
00793 
00794 
00795 void Foam::triSurfaceMesh::getNormal
00796 (
00797     const List<pointIndexHit>& info,
00798     vectorField& normal
00799 ) const
00800 {
00801     normal.setSize(info.size());
00802 
00803     forAll(info, i)
00804     {
00805         if (info[i].hit())
00806         {
00807             label triI = info[i].index();
00808             
00809             
00810 
00811             
00812             normal[i] = triSurface::operator[](triI).normal(points());
00813             normal[i] /= mag(normal[i]) + VSMALL;
00814         }
00815         else
00816         {
00817             
00818             normal[i] = vector::zero;
00819         }
00820     }
00821 }
00822 
00823 
00824 void Foam::triSurfaceMesh::setField(const labelList& values)
00825 {
00826     autoPtr<triSurfaceLabelField> fldPtr
00827     (
00828         new triSurfaceLabelField
00829         (
00830             IOobject
00831             (
00832                 "values",
00833                 objectRegistry::time().timeName(),  
00834                 "triSurface",                       
00835                 *this,
00836                 IOobject::NO_READ,
00837                 IOobject::AUTO_WRITE
00838             ),
00839             *this,
00840             dimless,
00841             labelField(values)
00842         )
00843     );
00844 
00845     
00846     fldPtr.ptr()->store();
00847 }
00848 
00849 
00850 void Foam::triSurfaceMesh::getField
00851 (
00852     const List<pointIndexHit>& info,
00853     labelList& values
00854 ) const
00855 {
00856     if (foundObject<triSurfaceLabelField>("values"))
00857     {
00858         values.setSize(info.size());
00859 
00860         const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
00861         (
00862             "values"
00863         );
00864 
00865         forAll(info, i)
00866         {
00867             if (info[i].hit())
00868             {
00869                 values[i] = fld[info[i].index()];
00870             }
00871         }
00872     }
00873 }
00874 
00875 
00876 void Foam::triSurfaceMesh::getVolumeType
00877 (
00878     const pointField& points,
00879     List<volumeType>& volType
00880 ) const
00881 {
00882     volType.setSize(points.size());
00883 
00884     scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00885     indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00886 
00887     forAll(points, pointI)
00888     {
00889         const point& pt = points[pointI];
00890 
00891         
00892         
00893         volType[pointI] = static_cast<volumeType>(tree().getVolumeType(pt));
00894     }
00895 
00896     indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00897 }
00898 
00899 
00900 
00901 bool Foam::triSurfaceMesh::writeObject
00902 (
00903     IOstream::streamFormat fmt,
00904     IOstream::versionNumber ver,
00905     IOstream::compressionType cmp
00906 ) const
00907 {
00908     fileName fullPath(searchableSurface::objectPath());
00909 
00910     if (!mkDir(fullPath.path()))
00911     {
00912         return false;
00913     }
00914 
00915     triSurface::write(fullPath);
00916 
00917     if (!isFile(fullPath))
00918     {
00919         return false;
00920     }
00921 
00922     
00923     return true;
00924 }
00925 
00926 
00927