1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "triSurfaceMesh.H"
29 #include "addToRunTimeSelectionTable.H"
31 #include "triSurfaceFields.H"
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(triSurfaceMesh, 0);
40 addToRunTimeSelectionTable(searchableSurface, triSurfaceMesh, dict);
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 //// Special version of Time::findInstance that does not check headerOk
47 //// to search for instances of raw files
48 //Foam::word Foam::triSurfaceMesh::findRawInstance
50 // const Time& runTime,
51 // const fileName& dir,
55 // // Check current time first
56 // if (isFile(runTime.path()/runTime.timeName()/dir/name))
58 // return runTime.timeName();
60 // instantList ts = runTime.times();
63 // for (instanceI = ts.size()-1; instanceI >= 0; --instanceI)
65 // if (ts[instanceI].value() <= runTime.timeOutputValue())
71 // // continue searching from here
72 // for (; instanceI >= 0; --instanceI)
74 // if (isFile(runTime.path()/ts[instanceI].name()/dir/name))
76 // return ts[instanceI].name();
81 // // not in any of the time directories, try constant
83 // // Note. This needs to be a hard-coded constant, rather than the
84 // // constant function of the time, because the latter points to
85 // // the case constant directory in parallel cases
87 // if (isFile(runTime.path()/runTime.constant()/dir/name))
89 // return runTime.constant();
94 // "searchableSurfaces::findRawInstance"
95 // "(const Time&, const fileName&, const word&)"
96 // ) << "Cannot find file \"" << name << "\" in directory "
97 // << runTime.constant()/dir
98 // << exit(FatalError);
100 // return runTime.constant();
104 //- Check file existence
105 const Foam::fileName& Foam::triSurfaceMesh::checkFile
107 const fileName& fName,
108 const fileName& objectName
115 "triSurfaceMesh::checkFile(const fileName&, const fileName&)"
116 ) << "Cannot find triSurfaceMesh starting from "
117 << objectName << exit(FatalError);
123 bool Foam::triSurfaceMesh::addFaceToEdge
126 EdgeMap<label>& facesPerEdge
129 EdgeMap<label>::iterator eFnd = facesPerEdge.find(e);
130 if (eFnd != facesPerEdge.end())
140 facesPerEdge.insert(e, 1);
146 bool Foam::triSurfaceMesh::isSurfaceClosed() const
148 // Construct pointFaces. Let's hope surface has compact point
150 labelListList pointFaces;
151 invertManyToMany(points().size(), *this, pointFaces);
153 // Loop over all faces surrounding point. Count edges emanating from point.
154 // Every edge should be used by two faces exactly.
155 // To prevent doing work twice per edge only look at edges to higher
157 EdgeMap<label> facesPerEdge(100);
158 forAll(pointFaces, pointI)
160 const labelList& pFaces = pointFaces[pointI];
162 facesPerEdge.clear();
165 const labelledTri& f = triSurface::operator[](pFaces[i]);
166 label fp = findIndex(f, pointI);
168 // Something weird: if I expand the code of addFaceToEdge in both
169 // below instances it gives a segmentation violation on some
170 // surfaces. Compiler (4.3.2) problem?
174 label nextPointI = f[f.fcIndex(fp)];
176 if (nextPointI > pointI)
178 bool okFace = addFaceToEdge
180 edge(pointI, nextPointI),
190 label prevPointI = f[f.rcIndex(fp)];
192 if (prevPointI > pointI)
194 bool okFace = addFaceToEdge
196 edge(pointI, prevPointI),
207 // Check for any edges used only once.
208 forAllConstIter(EdgeMap<label>, facesPerEdge, iter)
221 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
223 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s)
225 searchableSurface(io),
236 false // searchableSurface already registered under name
240 tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
245 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io)
247 // Find instance for triSurfaceMesh
248 searchableSurface(io),
253 // io.time().findInstance(io.local(), word::null),
258 // io.registerObject()
261 // Reused found instance in objectRegistry
267 static_cast<const searchableSurface&>(*this).instance(),
272 false // searchableSurface already registered under name
279 searchableSurface::filePath(),
280 searchableSurface::objectPath()
283 tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
288 Foam::triSurfaceMesh::triSurfaceMesh
291 const dictionary& dict
294 searchableSurface(io),
299 // io.time().findInstance(io.local(), word::null),
304 // io.registerObject()
307 // Reused found instance in objectRegistry
313 static_cast<const searchableSurface&>(*this).instance(),
318 false // searchableSurface already registered under name
325 searchableSurface::filePath(),
326 searchableSurface::objectPath()
329 tolerance_(indexedOctree<treeDataTriSurface>::perturbTol()),
332 scalar scaleFactor = 0;
334 // allow rescaling of the surface points
335 // eg, CAD geometries are often done in millimeters
336 if (dict.readIfPresent("scale", scaleFactor) && scaleFactor > 0)
338 Info<< searchableSurface::name() << " : using scale " << scaleFactor
340 triSurface::scalePoints(scaleFactor);
344 // Have optional non-standard search tolerance for gappy surfaces.
345 if (dict.readIfPresent("tolerance", tolerance_) && tolerance_ > 0)
347 Info<< searchableSurface::name() << " : using intersection tolerance "
348 << tolerance_ << endl;
353 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
355 Foam::triSurfaceMesh::~triSurfaceMesh()
361 void Foam::triSurfaceMesh::clearOut()
365 triSurface::clearOut();
369 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
371 void Foam::triSurfaceMesh::movePoints(const pointField& newPoints)
375 triSurface::movePoints(newPoints);
379 const Foam::indexedOctree<Foam::treeDataTriSurface>&
380 Foam::triSurfaceMesh::tree() const
384 // Random number generator. Bit dodgy since not exactly random ;-)
385 Random rndGen(65431);
387 // Slightly extended bb. Slightly off-centred just so on symmetric
388 // geometry there are less face/edge aligned items.
391 treeBoundBox(points(), meshPoints()).extend(rndGen, 1E-4)
393 bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
394 bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
396 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
397 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
401 new indexedOctree<treeDataTriSurface>
403 treeDataTriSurface(*this),
411 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
418 const Foam::indexedOctree<Foam::treeDataEdge>&
419 Foam::triSurfaceMesh::edgeTree() const
421 if (edgeTree_.empty())
434 // Random number generator. Bit dodgy since not exactly random ;-)
435 Random rndGen(65431);
437 // Slightly extended bb. Slightly off-centred just so on symmetric
438 // geometry there are less face/edge aligned items.
441 treeBoundBox(points(), meshPoints()).extend(rndGen, 1E-4)
443 bb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
444 bb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
448 new indexedOctree<treeDataEdge>
454 localPoints(), // points
455 bEdges // selected edges
468 const Foam::wordList& Foam::triSurfaceMesh::regions() const
470 if (regions_.empty())
472 regions_.setSize(patches().size());
473 forAll(regions_, regionI)
475 regions_[regionI] = patches()[regionI].name();
482 // Find out if surface is closed.
483 bool Foam::triSurfaceMesh::hasVolumeType() const
485 if (surfaceClosed_ == -1)
487 if (isSurfaceClosed())
497 return surfaceClosed_ == 1;
501 void Foam::triSurfaceMesh::findNearest
503 const pointField& samples,
504 const scalarField& nearestDistSqr,
505 List<pointIndexHit>& info
508 const indexedOctree<treeDataTriSurface>& octree = tree();
510 info.setSize(samples.size());
512 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
513 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
517 static_cast<pointIndexHit&>(info[i]) = octree.findNearest
524 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
528 void Foam::triSurfaceMesh::findLine
530 const pointField& start,
531 const pointField& end,
532 List<pointIndexHit>& info
535 const indexedOctree<treeDataTriSurface>& octree = tree();
537 info.setSize(start.size());
539 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
540 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
544 static_cast<pointIndexHit&>(info[i]) = octree.findLine
551 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
555 void Foam::triSurfaceMesh::findLineAny
557 const pointField& start,
558 const pointField& end,
559 List<pointIndexHit>& info
562 const indexedOctree<treeDataTriSurface>& octree = tree();
564 info.setSize(start.size());
566 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
567 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
571 static_cast<pointIndexHit&>(info[i]) = octree.findLineAny
578 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
582 void Foam::triSurfaceMesh::findLineAll
584 const pointField& start,
585 const pointField& end,
586 List<List<pointIndexHit> >& info
589 const indexedOctree<treeDataTriSurface>& octree = tree();
591 info.setSize(start.size());
593 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
594 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
597 DynamicList<pointIndexHit, 1, 1> hits;
600 // To find all intersections we add a small vector to the last intersection
601 // This is chosen such that
602 // - it is significant (SMALL is smallest representative relative tolerance;
603 // we need something bigger since we're doing calculations)
604 // - if the start-end vector is zero we still progress
605 const vectorField dirVec(end-start);
606 const scalarField magSqrDirVec(magSqr(dirVec));
607 const vectorField smallVec
609 indexedOctree<treeDataTriSurface>::perturbTol()*dirVec
610 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
613 forAll(start, pointI)
615 // See if any intersection between pt and end
616 pointIndexHit inter = octree.findLine(start[pointI], end[pointI]);
623 point pt = inter.hitPoint() + smallVec[pointI];
625 while (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
627 // See if any intersection between pt and end
628 pointIndexHit inter = octree.findLine(pt, end[pointI]);
630 // Check for not hit or hit same triangle as before (can happen
631 // if vector along surface of triangle)
635 || (inter.index() == hits[hits.size()-1].index())
642 pt = inter.hitPoint() + smallVec[pointI];
645 info[pointI].transfer(hits);
649 info[pointI].clear();
653 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
657 void Foam::triSurfaceMesh::getRegion
659 const List<pointIndexHit>& info,
663 region.setSize(info.size());
668 region[i] = triSurface::operator[](info[i].index()).region();
678 void Foam::triSurfaceMesh::getNormal
680 const List<pointIndexHit>& info,
684 normal.setSize(info.size());
690 label triI = info[i].index();
692 //normal[i] = faceNormals()[triI];
695 normal[i] = triSurface::operator[](triI).normal(points());
696 normal[i] /= mag(normal[i]) + VSMALL;
701 normal[i] = vector::zero;
707 void Foam::triSurfaceMesh::getField
709 const word& fieldName,
710 const List<pointIndexHit>& info,
714 const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
719 values.setSize(info.size());
724 values[i] = fld[info[i].index()];
730 void Foam::triSurfaceMesh::getVolumeType
732 const pointField& points,
733 List<volumeType>& volType
736 volType.setSize(points.size());
738 scalar oldTol = indexedOctree<treeDataTriSurface>::perturbTol();
739 indexedOctree<treeDataTriSurface>::perturbTol() = tolerance_;
741 forAll(points, pointI)
743 const point& pt = points[pointI];
745 // - use cached volume type per each tree node
746 // - cheat conversion since same values
747 volType[pointI] = static_cast<volumeType>(tree().getVolumeType(pt));
750 indexedOctree<treeDataTriSurface>::perturbTol() = oldTol;
754 //- Write using given format, version and compression
755 bool Foam::triSurfaceMesh::writeObject
757 IOstream::streamFormat fmt,
758 IOstream::versionNumber ver,
759 IOstream::compressionType cmp
762 fileName fullPath(searchableSurface::objectPath());
764 if (!mkDir(fullPath.path()))
769 triSurface::write(fullPath);
771 if (!isFile(fullPath))
776 //return objectRegistry::writeObject(fmt, ver, cmp);
781 // ************************************************************************* //