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