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
00027 #include "triSurfaceMesh.H"
00028 #include "Random.H"
00029 #include "addToRunTimeSelectionTable.H"
00030 #include "EdgeMap.H"
00031 #include "triSurfaceFields.H"
00032 #include "Time.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 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s)
00224 :
00225 searchableSurface(io),
00226 objectRegistry
00227 (
00228 IOobject
00229 (
00230 io.name(),
00231 io.instance(),
00232 io.local(),
00233 io.db(),
00234 io.readOpt(),
00235 io.writeOpt(),
00236 false
00237 )
00238 ),
00239 triSurface(s),
00240 tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
00241 surfaceClosed_(-1)
00242 {}
00243
00244
00245 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io)
00246 :
00247
00248 searchableSurface(io),
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 objectRegistry
00263 (
00264 IOobject
00265 (
00266 io.name(),
00267 static_cast<const searchableSurface&>(*this).instance(),
00268 io.local(),
00269 io.db(),
00270 io.readOpt(),
00271 io.writeOpt(),
00272 false
00273 )
00274 ),
00275 triSurface
00276 (
00277 checkFile
00278 (
00279 searchableSurface::filePath(),
00280 searchableSurface::objectPath()
00281 )
00282 ),
00283 tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
00284 surfaceClosed_(-1)
00285 {}
00286
00287
00288 Foam::triSurfaceMesh::triSurfaceMesh
00289 (
00290 const IOobject& io,
00291 const dictionary& dict
00292 )
00293 :
00294 searchableSurface(io),
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 objectRegistry
00309 (
00310 IOobject
00311 (
00312 io.name(),
00313 static_cast<const searchableSurface&>(*this).instance(),
00314 io.local(),
00315 io.db(),
00316 io.readOpt(),
00317 io.writeOpt(),
00318 false
00319 )
00320 ),
00321 triSurface
00322 (
00323 checkFile
00324 (
00325 searchableSurface::filePath(),
00326 searchableSurface::objectPath()
00327 )
00328 ),
00329 tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
00330 surfaceClosed_(-1)
00331 {
00332 scalar scaleFactor = 0;
00333
00334
00335
00336 if (dict.readIfPresent("scale", scaleFactor) && scaleFactor > 0)
00337 {
00338 Info<< searchableSurface::name() << " : using scale " << scaleFactor
00339 << endl;
00340 triSurface::scalePoints(scaleFactor);
00341 }
00342
00343
00344
00345 if (dict.readIfPresent("tolerance", tolerance_) && tolerance_ > 0)
00346 {
00347 Info<< searchableSurface::name() << " : using intersection tolerance "
00348 << tolerance_ << endl;
00349 }
00350 }
00351
00352
00353
00354
00355 Foam::triSurfaceMesh::~triSurfaceMesh()
00356 {
00357 clearOut();
00358 }
00359
00360
00361 void Foam::triSurfaceMesh::clearOut()
00362 {
00363 tree_.clear();
00364 edgeTree_.clear();
00365 triSurface::clearOut();
00366 }
00367
00368
00369
00370
00371 void Foam::triSurfaceMesh::movePoints(const pointField& newPoints)
00372 {
00373 tree_.clear();
00374 edgeTree_.clear();
00375 triSurface::movePoints(newPoints);
00376 }
00377
00378
00379 const Foam::indexedOctree<Foam::treeDataTriSurface>&
00380 Foam::triSurfaceMesh::tree() const
00381 {
00382 if (tree_.empty())
00383 {
00384
00385 Random rndGen(65431);
00386
00387
00388
00389 treeBoundBox bb
00390 (
00391 treeBoundBox(points(), meshPoints()).extend(rndGen, 1E-4)
00392 );
00393 bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00394 bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00395
00396 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00397 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00398
00399 tree_.reset
00400 (
00401 new indexedOctree<treeDataTriSurface>
00402 (
00403 treeDataTriSurface(*this),
00404 bb,
00405 10,
00406 10,
00407 3.0
00408 )
00409 );
00410
00411 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00412 }
00413
00414 return tree_();
00415 }
00416
00417
00418 const Foam::indexedOctree<Foam::treeDataEdge>&
00419 Foam::triSurfaceMesh::edgeTree() const
00420 {
00421 if (edgeTree_.empty())
00422 {
00423
00424 labelList bEdges
00425 (
00426 identity
00427 (
00428 nEdges()
00429 -nInternalEdges()
00430 )
00431 + nInternalEdges()
00432 );
00433
00434
00435 Random rndGen(65431);
00436
00437
00438
00439 treeBoundBox bb
00440 (
00441 treeBoundBox(points(), meshPoints()).extend(rndGen, 1E-4)
00442 );
00443 bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00444 bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00445
00446 edgeTree_.reset
00447 (
00448 new indexedOctree<treeDataEdge>
00449 (
00450 treeDataEdge
00451 (
00452 false,
00453 edges(),
00454 localPoints(),
00455 bEdges
00456 ),
00457 bb,
00458 8,
00459 10,
00460 3.0
00461 )
00462 );
00463 }
00464 return edgeTree_();
00465 }
00466
00467
00468 const Foam::wordList& Foam::triSurfaceMesh::regions() const
00469 {
00470 if (regions_.empty())
00471 {
00472 regions_.setSize(patches().size());
00473 forAll(regions_, regionI)
00474 {
00475 regions_[regionI] = patches()[regionI].name();
00476 }
00477 }
00478 return regions_;
00479 }
00480
00481
00482
00483 bool Foam::triSurfaceMesh::hasVolumeType() const
00484 {
00485 if (surfaceClosed_ == -1)
00486 {
00487 if (isSurfaceClosed())
00488 {
00489 surfaceClosed_ = 1;
00490 }
00491 else
00492 {
00493 surfaceClosed_ = 0;
00494 }
00495 }
00496
00497 return surfaceClosed_ == 1;
00498 }
00499
00500
00501 void Foam::triSurfaceMesh::findNearest
00502 (
00503 const pointField& samples,
00504 const scalarField& nearestDistSqr,
00505 List<pointIndexHit>& info
00506 ) const
00507 {
00508 const indexedOctree<treeDataTriSurface>& octree = tree();
00509
00510 info.setSize(samples.size());
00511
00512 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00513 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00514
00515 forAll(samples, i)
00516 {
00517 static_cast<pointIndexHit&>(info[i]) = octree.findNearest
00518 (
00519 samples[i],
00520 nearestDistSqr[i]
00521 );
00522 }
00523
00524 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00525 }
00526
00527
00528 void Foam::triSurfaceMesh::findLine
00529 (
00530 const pointField& start,
00531 const pointField& end,
00532 List<pointIndexHit>& info
00533 ) const
00534 {
00535 const indexedOctree<treeDataTriSurface>& octree = tree();
00536
00537 info.setSize(start.size());
00538
00539 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00540 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00541
00542 forAll(start, i)
00543 {
00544 static_cast<pointIndexHit&>(info[i]) = octree.findLine
00545 (
00546 start[i],
00547 end[i]
00548 );
00549 }
00550
00551 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00552 }
00553
00554
00555 void Foam::triSurfaceMesh::findLineAny
00556 (
00557 const pointField& start,
00558 const pointField& end,
00559 List<pointIndexHit>& info
00560 ) const
00561 {
00562 const indexedOctree<treeDataTriSurface>& octree = tree();
00563
00564 info.setSize(start.size());
00565
00566 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00567 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00568
00569 forAll(start, i)
00570 {
00571 static_cast<pointIndexHit&>(info[i]) = octree.findLineAny
00572 (
00573 start[i],
00574 end[i]
00575 );
00576 }
00577
00578 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00579 }
00580
00581
00582 void Foam::triSurfaceMesh::findLineAll
00583 (
00584 const pointField& start,
00585 const pointField& end,
00586 List<List<pointIndexHit> >& info
00587 ) const
00588 {
00589 const indexedOctree<treeDataTriSurface>& octree = tree();
00590
00591 info.setSize(start.size());
00592
00593 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00594 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00595
00596
00597 DynamicList<pointIndexHit, 1, 1> hits;
00598
00599
00600
00601
00602
00603
00604
00605 const vectorField dirVec(end-start);
00606 const scalarField magSqrDirVec(magSqr(dirVec));
00607 const vectorField smallVec
00608 (
00609 indexedOctree<treeDataTriSurface>::perturbTol()*dirVec
00610 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
00611 );
00612
00613 forAll(start, pointI)
00614 {
00615
00616 pointIndexHit inter = octree.findLine(start[pointI], end[pointI]);
00617
00618 if (inter.hit())
00619 {
00620 hits.clear();
00621 hits.append(inter);
00622
00623 point pt = inter.hitPoint() + smallVec[pointI];
00624
00625 while (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
00626 {
00627
00628 pointIndexHit inter = octree.findLine(pt, end[pointI]);
00629
00630
00631
00632 if
00633 (
00634 !inter.hit()
00635 || (inter.index() == hits[hits.size()-1].index())
00636 )
00637 {
00638 break;
00639 }
00640 hits.append(inter);
00641
00642 pt = inter.hitPoint() + smallVec[pointI];
00643 }
00644
00645 info[pointI].transfer(hits);
00646 }
00647 else
00648 {
00649 info[pointI].clear();
00650 }
00651 }
00652
00653 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00654 }
00655
00656
00657 void Foam::triSurfaceMesh::getRegion
00658 (
00659 const List<pointIndexHit>& info,
00660 labelList& region
00661 ) const
00662 {
00663 region.setSize(info.size());
00664 forAll(info, i)
00665 {
00666 if (info[i].hit())
00667 {
00668 region[i] = triSurface::operator[](info[i].index()).region();
00669 }
00670 else
00671 {
00672 region[i] = -1;
00673 }
00674 }
00675 }
00676
00677
00678 void Foam::triSurfaceMesh::getNormal
00679 (
00680 const List<pointIndexHit>& info,
00681 vectorField& normal
00682 ) const
00683 {
00684 normal.setSize(info.size());
00685
00686 forAll(info, i)
00687 {
00688 if (info[i].hit())
00689 {
00690 label triI = info[i].index();
00691
00692
00693
00694
00695 normal[i] = triSurface::operator[](triI).normal(points());
00696 normal[i] /= mag(normal[i]) + VSMALL;
00697 }
00698 else
00699 {
00700
00701 normal[i] = vector::zero;
00702 }
00703 }
00704 }
00705
00706
00707 void Foam::triSurfaceMesh::getField
00708 (
00709 const word& fieldName,
00710 const List<pointIndexHit>& info,
00711 labelList& values
00712 ) const
00713 {
00714 const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
00715 (
00716 fieldName
00717 );
00718
00719 values.setSize(info.size());
00720 forAll(info, i)
00721 {
00722 if (info[i].hit())
00723 {
00724 values[i] = fld[info[i].index()];
00725 }
00726 }
00727 }
00728
00729
00730 void Foam::triSurfaceMesh::getVolumeType
00731 (
00732 const pointField& points,
00733 List<volumeType>& volType
00734 ) const
00735 {
00736 volType.setSize(points.size());
00737
00738 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
00739 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
00740
00741 forAll(points, pointI)
00742 {
00743 const point& pt = points[pointI];
00744
00745
00746
00747 volType[pointI] = static_cast<volumeType>(tree().getVolumeType(pt));
00748 }
00749
00750 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
00751 }
00752
00753
00754
00755 bool Foam::triSurfaceMesh::writeObject
00756 (
00757 IOstream::streamFormat fmt,
00758 IOstream::versionNumber ver,
00759 IOstream::compressionType cmp
00760 ) const
00761 {
00762 fileName fullPath(searchableSurface::objectPath());
00763
00764 if (!mkDir(fullPath.path()))
00765 {
00766 return false;
00767 }
00768
00769 triSurface::write(fullPath);
00770
00771 if (!isFile(fullPath))
00772 {
00773 return false;
00774 }
00775
00776
00777 return true;
00778 }
00779
00780
00781