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
27 \*---------------------------------------------------------------------------*/
34 #include "linePointRef.H"
35 #include "pointIndexHit.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 Foam::string Foam::octree<Type>::volType(const label type)
46 else if (type == MIXED)
50 else if (type == INSIDE)
54 else if (type == OUTSIDE)
60 FatalErrorIn("volType(const label)") << "type:" << type
61 << " unknown." << abort(FatalError);
68 // Determine inside/outside status of vector compared to geometry-based normal
70 Foam::label Foam::octree<Type>::getVolType
72 const vector& geomNormal,
76 scalar sign = geomNormal & vec;
80 return octree<Type>::OUTSIDE;
84 return octree<Type>::INSIDE;
89 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
92 Foam::octree<Type>::octree
94 const treeBoundBox& octreeBb,
96 const label minNLevels,
97 const scalar maxLeafRatio,
98 const scalar maxShapeRatio
101 topNode_(new treeNode<Type>(octreeBb)),
104 maxLeafRatio_(maxLeafRatio),
105 maxShapeRatio_(maxShapeRatio),
106 minNLevels_(minNLevels),
112 endConstIter_(*this, -1)
116 setNodes(nNodes() + 1);
118 const label nShapes = shapes_.size();
120 labelList indices(nShapes);
121 for (label i = 0; i < nShapes; i++)
126 // Create initial level (0) of subLeaves
129 Pout<< "octree : --- Start of Level " << deepestLevel_
132 topNode_->distribute(0, *this, shapes_, indices);
137 Pout<< "octree : --- End of Level " << deepestLevel_
141 // Breadth first creation of tree
142 // Stop if: - level above minlevel and
143 // - less than so many cells per endpoint
144 // (so bottom level is fine enough)
145 // - every shape mentioned in only so many
146 // leaves. (if shape bb quite big it will end up
147 // in lots of leaves).
148 // - no change in number of leaves
149 // (happens if leafs fine enough)
150 // This guarantees that tree
151 // - is fine enough (if minLevel > 0)
152 // - has some guaranteed maximum size (maxShapeRatio)
154 label oldNLeaves = -1; // make test below pass first time.
158 (deepestLevel_ <= minNLevels_)
160 (nEntries() > maxLeafRatio * nLeaves()) // shapes per leaf
161 && (nEntries() < maxShapeRatio * nShapes) // entries per shape
165 if (deepestLevel_ >= maxNLevels)
169 Pout<< "octree : exiting since maxNLevels "
170 << maxNLevels << " reached" << endl;
175 if (oldNLeaves == nLeaves())
179 Pout<< "octree : exiting since nLeaves does not change"
186 Pout<< "octree : --- Start of Level " << deepestLevel_
190 oldNLeaves = nLeaves();
192 topNode_->redistribute
204 Pout<< "octree : --- End of Level " << deepestLevel_
214 Pout<< "octree : Constructed octree in = "
215 << timer.cpuTimeIncrement()
216 << " s\n" << endl << endl;
219 // Set volume type of non-treeleaf nodes.
220 topNode_->setSubNodeType(0, *this, shapes_);
224 Pout<< "octree : Added node information to octree in = "
225 << timer.cpuTimeIncrement()
226 << " s\n" << endl << endl;
231 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
233 template <class Type>
234 Foam::octree<Type>::~octree()
240 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
242 template <class Type>
243 Foam::label Foam::octree<Type>::getSampleType(const point& sample) const
245 return topNode_->getSampleType(0, *this, shapes_, sample);
249 template <class Type>
250 Foam::label Foam::octree<Type>::find(const point& sample) const
252 return topNode_->find(shapes_, sample);
256 template <class Type>
257 bool Foam::octree<Type>::findTightest
260 treeBoundBox& tightest
263 return topNode_->findTightest
272 template <class Type>
273 Foam::label Foam::octree<Type>::findNearest
276 treeBoundBox& tightest,
280 label tightestI = -1;
284 Pout<< "octree::findNearest : searching for nearest for "
285 << "sample:" << sample
286 << " tightest:" << tightest << endl;
289 topNode_->findNearest
300 Pout<< "octree::findNearest : found nearest for "
301 << "sample:" << sample << " with "
302 << " tightestI:" << tightestI
303 << " tightest:" << tightest
304 << " tightestDist:" << tightestDist
312 template <class Type>
313 Foam::label Foam::octree<Type>::findNearest
315 const linePointRef& ln,
316 treeBoundBox& tightest,
321 // Start off from miss with points at large distance apart.
322 label tightestI = -1;
323 linePoint = point(-GREAT, -GREAT, -GREAT);
324 shapePoint = point(GREAT, GREAT, GREAT);
326 topNode_->findNearest
340 template <class Type>
341 Foam::labelList Foam::octree<Type>::findBox(const boundBox& bb) const
343 // Storage for labels of shapes inside bb. Size estimate.
344 labelHashSet elements(100);
346 topNode_->findBox(shapes_, bb, elements);
348 return elements.toc();
352 template <class Type>
353 Foam::pointIndexHit Foam::octree<Type>::findLine
355 const point& treeStart,
359 // Initialize to a miss
360 pointIndexHit hitInfo(false, treeStart, -1);
362 const vector dir(treeEnd - treeStart);
364 // Current line segment to search
365 point start(treeStart);
370 // Find nearest treeLeaf intersected by line
373 const treeLeaf<Type>* leafPtr = findLeafLine
382 // Reached end of string of treeLeaves to be searched. Return
383 // whatever we have found so far.
387 // Inside treeLeaf find nearest intersection
390 const labelList& indices = leafPtr->indices();
392 forAll(indices, elemI)
394 label index = indices[elemI];
397 bool hit = shapes().intersects(index, start, end, pt);
401 // Check whether intersection nearer p
402 scalar s = (pt - treeStart) & dir;
410 hitInfo.setPoint(pt);
411 hitInfo.setIndex(index);
413 // Update segment to search
421 // Found intersected shape.
425 // Start from end of current leaf
426 start = leafIntPoint;
433 template <class Type>
434 Foam::pointIndexHit Foam::octree<Type>::findLineAny
440 // Initialize to a miss
441 pointIndexHit hitInfo(false, start, -1);
443 // Start of segment in current treeNode.
447 // Find treeLeaf intersected by line
450 const treeLeaf<Type>* leafPtr = findLeafLine(p, end, leafIntPoint);
454 // Reached end of string of treeLeaves to be searched. Return
455 // whatever we have found so far.
459 // Inside treeLeaf find any intersection
461 // Vector from endPoint to entry point of leaf.
462 const vector edgeVec(end - p);
464 const labelList& indices = leafPtr->indices();
466 forAll(indices, elemI)
468 label index = indices[elemI];
471 bool hit = shapes().intersects
482 hitInfo.setPoint(pt);
483 hitInfo.setIndex(index);
491 // Found intersected shape.
495 // Start from end of current leaf
503 template <class Type>
504 const Foam::treeLeaf<Type>* Foam::octree<Type>::findLeafLine
511 // returns first found cube along line
515 Pout<< "octree::findLeafLine : searching for shapes on line "
517 << " end:" << end << endl;
520 // If start is outside project onto top cube
521 if (octreeBb_.contains(start))
523 leafIntPoint = start;
527 if (!octreeBb_.intersects(start, end, leafIntPoint))
531 Pout<< "octree::findLeafLine : start outside domain but does"
532 << " not intersect : start:"
540 Pout<< "octree::findLeafLine : start propagated to inside"
542 << leafIntPoint << endl;
546 // Normal action: find next intersection along line
547 const treeLeaf<Type>* leafPtr = topNode_->findLeafLine
557 Pout<< "returning from octree::findLeafLine with "
558 << "leafIntersection:" << leafIntPoint
559 << " leafPtr:" << long(leafPtr) << endl;
566 template <class Type>
567 void Foam::octree<Type>::writeOBJ
573 scalar minx = octreeBb_.min().x();
574 scalar miny = octreeBb_.min().y();
575 scalar minz = octreeBb_.min().z();
577 scalar maxx = octreeBb_.max().x();
578 scalar maxy = octreeBb_.max().y();
579 scalar maxz = octreeBb_.max().z();
581 os << "v " << minx << " " << miny << " " << minz << endl;
582 os << "v " << maxx << " " << miny << " " << minz << endl;
583 os << "v " << maxx << " " << maxy << " " << minz << endl;
584 os << "v " << minx << " " << maxy << " " << minz << endl;
586 os << "v " << minx << " " << miny << " " << maxz << endl;
587 os << "v " << maxx << " " << miny << " " << maxz << endl;
588 os << "v " << maxx << " " << maxy << " " << maxz << endl;
589 os << "v " << minx << " " << maxy << " " << maxz << endl;
592 os << "l " << vertNo + 1 << " " << vertNo + 2 << endl;
593 os << "l " << vertNo + 2 << " " << vertNo + 3 << endl;
594 os << "l " << vertNo + 3 << " " << vertNo + 4 << endl;
595 os << "l " << vertNo + 4 << " " << vertNo + 1 << endl;
598 os << "l " << vertNo + 5 << " " << vertNo + 6 << endl;
599 os << "l " << vertNo + 6 << " " << vertNo + 7 << endl;
600 os << "l " << vertNo + 7 << " " << vertNo + 8 << endl;
601 os << "l " << vertNo + 8 << " " << vertNo + 5 << endl;
603 // Edges from bottom to top face
604 os << "l " << vertNo + 1 << " " << vertNo + 5 << endl;
605 os << "l " << vertNo + 2 << " " << vertNo + 6 << endl;
606 os << "l " << vertNo + 3 << " " << vertNo + 7 << endl;
607 os << "l " << vertNo + 4 << " " << vertNo + 8 << endl;
611 topNode_->writeOBJ(os, 1, vertNo);
615 template <class Type>
616 void Foam::octree<Type>::printStats(Ostream& os) const
618 os << "Statistics after iteration " << deepestLevel() << ':' << endl
619 << " nShapes :" << shapes().size() << endl
620 << " nNodes :" << nNodes() << endl
621 << " nLeaves :" << nLeaves() << endl
622 << " nEntries :" << nEntries() << endl;
624 if (nLeaves() && shapes().size())
627 << " Cells per leaf :"
628 << scalar(nEntries())/nLeaves()
630 << " Every cell in :"
631 << scalar(nEntries())/shapes().size() << " cubes"
637 // * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * * //
639 // Construct from a octree. Set index at end.
640 template <class Type>
641 Foam::octree<Type>::iterator::iterator(octree<Type>& oc)
644 curLeaf_(oc.nLeaves())
650 // Construct from octree. Set index.
651 template <class Type>
652 Foam::octree<Type>::iterator::iterator(octree<Type>& oc, label index)
659 leaves_.setSize(oc.nLeaves());
662 octree_.topNode()->findLeaves(leaves_, leafIndex);
664 if (leafIndex != oc.nLeaves())
668 "octree::iterator::iterator"
671 << "Traversal of tree returns : " << leafIndex << endl
672 << "Statistics of octree say : " << oc.nLeaves() << endl
673 << abort(FatalError);
679 template <class Type>
680 void Foam::octree<Type>::iterator::operator=(const iterator& iter)
682 if ((curLeaf_ < 0) && (iter.curLeaf_ >= 0))
686 "octree::iterator::operator="
689 << "lhs : " << curLeaf_ << endl
690 << "rhs : " << iter.curLeaf_ << endl
691 << abort(FatalError);
693 curLeaf_ = iter.curLeaf_;
697 template <class Type>
698 bool Foam::octree<Type>::iterator::operator==(const iterator& iter) const
701 (curLeaf_ >= 0 ? curLeaf_ : octree_.nLeaves());
703 (iter.curLeaf_ >= 0 ? iter.curLeaf_ : iter.octree_.nLeaves());
705 return index1 == index2;
709 template <class Type>
710 bool Foam::octree<Type>::iterator::operator!=(const iterator& iter) const
712 return !(iterator::operator==(iter));
716 template <class Type>
717 Foam::treeLeaf<Type>& Foam::octree<Type>::iterator::operator*()
719 return *leaves_[curLeaf_];
723 template <class Type>
724 typename Foam::octree<Type>::iterator&
725 Foam::octree<Type>::iterator::operator++()
732 template <class Type>
733 typename Foam::octree<Type>::iterator
734 Foam::octree<Type>::iterator::operator++(int)
736 iterator tmp = *this;
742 template <class Type>
743 typename Foam::octree<Type>::iterator
744 Foam::octree<Type>::begin()
746 return iterator(*this, 0);
750 template <class Type>
751 const typename Foam::octree<Type>::iterator&
752 Foam::octree<Type>::end()
754 return octree<Type>::endIter_;
758 // * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * * //
760 // Construct for a given octree
761 template <class Type>
762 Foam::octree<Type>::const_iterator::const_iterator(const octree<Type>& oc)
765 curLeaf_(oc.nLeaves())
767 leaves_.setSize(oc.nLeaves());
771 // Construct for a given octree
772 template <class Type>
773 Foam::octree<Type>::const_iterator::const_iterator
775 const octree<Type>& oc,
784 leaves_.setSize(oc.nLeaves());
787 octree_.topNode()->findLeaves(leaves_, leafIndex);
789 if (leafIndex != oc.nLeaves())
793 "octree::const_iterator::const_iterator"
796 << "Traversal of tree returns : " << leafIndex << endl
797 << "Statistics of octree say : " << oc.nLeaves() << endl
798 << abort(FatalError);
804 template <class Type>
805 void Foam::octree<Type>::const_iterator::operator=(const const_iterator& iter)
807 if ((curLeaf_ < 0) && (iter.curLeaf_ >= 0))
811 "octree::const_iterator::operator="
812 "(const const_iterator&)"
814 << "lhs : " << curLeaf_ << endl
815 << "rhs : " << iter.curLeaf_ << endl
816 << abort(FatalError);
818 curLeaf_ = iter.curLeaf_;
819 curLeaf_ = iter.curLeaf_;
823 template <class Type>
824 bool Foam::octree<Type>::const_iterator::operator==
826 const const_iterator& iter
830 (curLeaf_ >= 0 ? curLeaf_ : octree_.nLeaves());
832 (iter.curLeaf_ >= 0 ? iter.curLeaf_ : iter.octree_.nLeaves());
834 return index1 == index2;
838 template <class Type>
839 bool Foam::octree<Type>::const_iterator::operator!=
841 const const_iterator& iter
844 return !(const_iterator::operator==(iter));
848 template <class Type>
849 const Foam::treeLeaf<Type>& Foam::octree<Type>::const_iterator::operator*()
851 return *leaves_[curLeaf_];
855 template <class Type>
856 typename Foam::octree<Type>::const_iterator&
857 Foam::octree<Type>::const_iterator::operator++()
864 template <class Type>
865 typename Foam::octree<Type>::const_iterator
866 Foam::octree<Type>::const_iterator::operator++(int)
868 const_iterator tmp = *this;
874 template <class Type>
875 typename Foam::octree<Type>::const_iterator
876 Foam::octree<Type>::begin() const
878 return const_iterator(*this, 0);
882 template <class Type>
883 typename Foam::octree<Type>::const_iterator
884 Foam::octree<Type>::cbegin() const
886 return const_iterator(*this, 0);
890 template <class Type>
891 const typename Foam::octree<Type>::const_iterator&
892 Foam::octree<Type>::end() const
894 return octree<Type>::endConstIter_;
898 template <class Type>
899 const typename Foam::octree<Type>::const_iterator&
900 Foam::octree<Type>::cend() const
902 return octree<Type>::endConstIter_;
906 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
908 template <class Type>
909 Foam::Ostream& Foam::operator<<(Ostream& os, const octree<Type>& oc)
911 return os << token::BEGIN_LIST
912 //<< token::SPACE << oc.shapes_
913 << token::SPACE << oc.octreeBb_
914 << token::SPACE << oc.maxLeafRatio_
915 << token::SPACE << oc.maxShapeRatio_
916 << token::SPACE << oc.minNLevels_
917 << token::SPACE << oc.deepestLevel_
918 << token::SPACE << oc.nEntries_
919 << token::SPACE << oc.nNodes_
920 << token::SPACE << oc.nLeaves_
921 << token::SPACE << *oc.topNode_
922 << token::SPACE << token::END_LIST;
926 // ************************************************************************* //