1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
31 #include "linePointRef.H"
32 #include "pointIndexHit.H"
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 Foam::string Foam::octree<Type>::volType(const label type)
43 else if (type == MIXED)
47 else if (type == INSIDE)
51 else if (type == OUTSIDE)
57 FatalErrorIn("volType(const label)") << "type:" << type
58 << " unknown." << abort(FatalError);
65 // Determine inside/outside status of vector compared to geometry-based normal
67 Foam::label Foam::octree<Type>::getVolType
69 const vector& geomNormal,
73 scalar sign = geomNormal & vec;
77 return octree<Type>::OUTSIDE;
81 return octree<Type>::INSIDE;
86 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
89 Foam::octree<Type>::octree
91 const treeBoundBox& octreeBb,
93 const label minNLevels,
94 const scalar maxLeafRatio,
95 const scalar maxShapeRatio
98 topNode_(new treeNode<Type>(octreeBb)),
101 maxLeafRatio_(maxLeafRatio),
102 maxShapeRatio_(maxShapeRatio),
103 minNLevels_(minNLevels),
109 endConstIter_(*this, -1)
113 setNodes(nNodes() + 1);
115 const label nShapes = shapes_.size();
117 labelList indices(nShapes);
118 for (label i = 0; i < nShapes; i++)
123 // Create initial level (0) of subLeaves
126 Pout<< "octree : --- Start of Level " << deepestLevel_
129 topNode_->distribute(0, *this, shapes_, indices);
134 Pout<< "octree : --- End of Level " << deepestLevel_
138 // Breadth first creation of tree
139 // Stop if: - level above minlevel and
140 // - less than so many cells per endpoint
141 // (so bottom level is fine enough)
142 // - every shape mentioned in only so many
143 // leaves. (if shape bb quite big it will end up
144 // in lots of leaves).
145 // - no change in number of leaves
146 // (happens if leafs fine enough)
147 // This guarantees that tree
148 // - is fine enough (if minLevel > 0)
149 // - has some guaranteed maximum size (maxShapeRatio)
151 label oldNLeaves = -1; // make test below pass first time.
152 label oldNNodes = -1;
156 (deepestLevel_ <= minNLevels_)
158 (nEntries() > maxLeafRatio * nLeaves()) // shapes per leaf
159 && (nEntries() < maxShapeRatio * nShapes) // entries per shape
163 if (deepestLevel_ >= maxNLevels)
167 Pout<< "octree : exiting since maxNLevels "
168 << maxNLevels << " reached" << endl;
173 if ((oldNLeaves == nLeaves()) && (oldNNodes == nNodes()))
177 Pout<< "octree : exiting since nLeaves and nNodes do not change"
184 Pout<< "octree : --- Start of Level " << deepestLevel_
188 oldNLeaves = nLeaves();
189 oldNNodes = nNodes();
191 topNode_->redistribute
203 Pout<< "octree : --- End of Level " << deepestLevel_
213 Pout<< "octree : Constructed octree in = "
214 << timer.cpuTimeIncrement()
215 << " s\n" << endl << endl;
218 // Set volume type of non-treeleaf nodes.
219 topNode_->setSubNodeType(0, *this, shapes_);
223 Pout<< "octree : Added node information to octree in = "
224 << timer.cpuTimeIncrement()
225 << " s\n" << endl << endl;
230 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
232 template <class Type>
233 Foam::octree<Type>::~octree()
239 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
241 template <class Type>
242 Foam::label Foam::octree<Type>::getSampleType(const point& sample) const
244 return topNode_->getSampleType(0, *this, shapes_, sample);
248 template <class Type>
249 Foam::label Foam::octree<Type>::find(const point& sample) const
251 return topNode_->find(shapes_, sample);
255 template <class Type>
256 bool Foam::octree<Type>::findTightest
259 treeBoundBox& tightest
262 return topNode_->findTightest
271 template <class Type>
272 Foam::label Foam::octree<Type>::findNearest
275 treeBoundBox& tightest,
279 label tightestI = -1;
283 Pout<< "octree::findNearest : searching for nearest for "
284 << "sample:" << sample
285 << " tightest:" << tightest << endl;
288 topNode_->findNearest
299 Pout<< "octree::findNearest : found nearest for "
300 << "sample:" << sample << " with "
301 << " tightestI:" << tightestI
302 << " tightest:" << tightest
303 << " tightestDist:" << tightestDist
311 template <class Type>
312 Foam::label Foam::octree<Type>::findNearest
314 const linePointRef& ln,
315 treeBoundBox& tightest,
320 // Start off from miss with points at large distance apart.
321 label tightestI = -1;
322 linePoint = point(-GREAT, -GREAT, -GREAT);
323 shapePoint = point(GREAT, GREAT, GREAT);
325 topNode_->findNearest
339 template <class Type>
340 Foam::labelList Foam::octree<Type>::findBox(const boundBox& bb) const
342 // Storage for labels of shapes inside bb. Size estimate.
343 labelHashSet elements(100);
345 topNode_->findBox(shapes_, bb, elements);
347 return elements.toc();
351 template <class Type>
352 Foam::pointIndexHit Foam::octree<Type>::findLine
354 const point& treeStart,
358 // Initialize to a miss
359 pointIndexHit hitInfo(false, treeStart, -1);
361 const vector dir(treeEnd - treeStart);
363 // Current line segment to search
364 point start(treeStart);
369 // Find nearest treeLeaf intersected by line
372 const treeLeaf<Type>* leafPtr = findLeafLine
381 // Reached end of string of treeLeaves to be searched. Return
382 // whatever we have found so far.
386 // Inside treeLeaf find nearest intersection
389 const labelList& indices = leafPtr->indices();
391 forAll(indices, elemI)
393 label index = indices[elemI];
396 bool hit = shapes().intersects(index, start, end, pt);
400 // Check whether intersection nearer p
401 scalar s = (pt - treeStart) & dir;
409 hitInfo.setPoint(pt);
410 hitInfo.setIndex(index);
412 // Update segment to search
420 // Found intersected shape.
424 // Start from end of current leaf
425 start = leafIntPoint;
432 template <class Type>
433 Foam::pointIndexHit Foam::octree<Type>::findLineAny
439 // Initialize to a miss
440 pointIndexHit hitInfo(false, start, -1);
442 // Start of segment in current treeNode.
446 // Find treeLeaf intersected by line
449 const treeLeaf<Type>* leafPtr = findLeafLine(p, end, leafIntPoint);
453 // Reached end of string of treeLeaves to be searched. Return
454 // whatever we have found so far.
458 // Inside treeLeaf find any intersection
460 // Vector from endPoint to entry point of leaf.
461 const vector edgeVec(end - p);
463 const labelList& indices = leafPtr->indices();
465 forAll(indices, elemI)
467 label index = indices[elemI];
470 bool hit = shapes().intersects
481 hitInfo.setPoint(pt);
482 hitInfo.setIndex(index);
490 // Found intersected shape.
494 // Start from end of current leaf
502 template <class Type>
503 const Foam::treeLeaf<Type>* Foam::octree<Type>::findLeafLine
510 // returns first found cube along line
514 Pout<< "octree::findLeafLine : searching for shapes on line "
516 << " end:" << end << endl;
519 // If start is outside project onto top cube
520 if (octreeBb_.contains(start))
522 leafIntPoint = start;
526 if (!octreeBb_.intersects(start, end, leafIntPoint))
530 Pout<< "octree::findLeafLine : start outside domain but does"
531 << " not intersect : start:"
539 Pout<< "octree::findLeafLine : start propagated to inside"
541 << leafIntPoint << endl;
545 // Normal action: find next intersection along line
546 const treeLeaf<Type>* leafPtr = topNode_->findLeafLine
556 Pout<< "returning from octree::findLeafLine with "
557 << "leafIntersection:" << leafIntPoint
558 << " leafPtr:" << long(leafPtr) << endl;
565 template <class Type>
566 void Foam::octree<Type>::writeOBJ
572 scalar minx = octreeBb_.min().x();
573 scalar miny = octreeBb_.min().y();
574 scalar minz = octreeBb_.min().z();
576 scalar maxx = octreeBb_.max().x();
577 scalar maxy = octreeBb_.max().y();
578 scalar maxz = octreeBb_.max().z();
580 os << "v " << minx << " " << miny << " " << minz << endl;
581 os << "v " << maxx << " " << miny << " " << minz << endl;
582 os << "v " << maxx << " " << maxy << " " << minz << endl;
583 os << "v " << minx << " " << maxy << " " << minz << endl;
585 os << "v " << minx << " " << miny << " " << maxz << endl;
586 os << "v " << maxx << " " << miny << " " << maxz << endl;
587 os << "v " << maxx << " " << maxy << " " << maxz << endl;
588 os << "v " << minx << " " << maxy << " " << maxz << endl;
591 os << "l " << vertNo + 1 << " " << vertNo + 2 << endl;
592 os << "l " << vertNo + 2 << " " << vertNo + 3 << endl;
593 os << "l " << vertNo + 3 << " " << vertNo + 4 << endl;
594 os << "l " << vertNo + 4 << " " << vertNo + 1 << endl;
597 os << "l " << vertNo + 5 << " " << vertNo + 6 << endl;
598 os << "l " << vertNo + 6 << " " << vertNo + 7 << endl;
599 os << "l " << vertNo + 7 << " " << vertNo + 8 << endl;
600 os << "l " << vertNo + 8 << " " << vertNo + 5 << endl;
602 // Edges from bottom to top face
603 os << "l " << vertNo + 1 << " " << vertNo + 5 << endl;
604 os << "l " << vertNo + 2 << " " << vertNo + 6 << endl;
605 os << "l " << vertNo + 3 << " " << vertNo + 7 << endl;
606 os << "l " << vertNo + 4 << " " << vertNo + 8 << endl;
610 topNode_->writeOBJ(os, 1, vertNo);
614 template <class Type>
615 void Foam::octree<Type>::printStats(Ostream& os) const
617 os << "Statistics after iteration " << deepestLevel() << ':' << endl
618 << " nShapes :" << shapes().size() << endl
619 << " nNodes :" << nNodes() << endl
620 << " nLeaves :" << nLeaves() << endl
621 << " nEntries :" << nEntries() << endl;
623 if (nLeaves() && shapes().size())
626 << " Cells per leaf :"
627 << scalar(nEntries())/nLeaves()
629 << " Every cell in :"
630 << scalar(nEntries())/shapes().size() << " cubes"
636 // * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * * //
638 // Construct from a octree. Set index at end.
639 template <class Type>
640 Foam::octree<Type>::iterator::iterator(octree<Type>& oc)
643 curLeaf_(oc.nLeaves())
649 // Construct from octree. Set index.
650 template <class Type>
651 Foam::octree<Type>::iterator::iterator(octree<Type>& oc, label index)
658 leaves_.setSize(oc.nLeaves());
661 octree_.topNode()->findLeaves(leaves_, leafIndex);
663 if (leafIndex != oc.nLeaves())
667 "octree::iterator::iterator"
670 << "Traversal of tree returns : " << leafIndex << endl
671 << "Statistics of octree say : " << oc.nLeaves() << endl
672 << abort(FatalError);
678 template <class Type>
679 void Foam::octree<Type>::iterator::operator=(const iterator& iter)
681 if ((curLeaf_ < 0) && (iter.curLeaf_ >= 0))
685 "octree::iterator::operator="
688 << "lhs : " << curLeaf_ << endl
689 << "rhs : " << iter.curLeaf_ << endl
690 << abort(FatalError);
692 curLeaf_ = iter.curLeaf_;
696 template <class Type>
697 bool Foam::octree<Type>::iterator::operator==(const iterator& iter) const
700 (curLeaf_ >= 0 ? curLeaf_ : octree_.nLeaves());
702 (iter.curLeaf_ >= 0 ? iter.curLeaf_ : iter.octree_.nLeaves());
704 return index1 == index2;
708 template <class Type>
709 bool Foam::octree<Type>::iterator::operator!=(const iterator& iter) const
711 return !(iterator::operator==(iter));
715 template <class Type>
716 Foam::treeLeaf<Type>& Foam::octree<Type>::iterator::operator*()
718 return *leaves_[curLeaf_];
722 template <class Type>
723 typename Foam::octree<Type>::iterator&
724 Foam::octree<Type>::iterator::operator++()
731 template <class Type>
732 typename Foam::octree<Type>::iterator
733 Foam::octree<Type>::iterator::operator++(int)
735 iterator tmp = *this;
741 template <class Type>
742 typename Foam::octree<Type>::iterator
743 Foam::octree<Type>::begin()
745 return iterator(*this, 0);
749 template <class Type>
750 const typename Foam::octree<Type>::iterator&
751 Foam::octree<Type>::end()
753 return octree<Type>::endIter_;
757 // * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * * //
759 // Construct for a given octree
760 template <class Type>
761 Foam::octree<Type>::const_iterator::const_iterator(const octree<Type>& oc)
764 curLeaf_(oc.nLeaves())
766 leaves_.setSize(oc.nLeaves());
770 // Construct for a given octree
771 template <class Type>
772 Foam::octree<Type>::const_iterator::const_iterator
774 const octree<Type>& oc,
783 leaves_.setSize(oc.nLeaves());
786 octree_.topNode()->findLeaves(leaves_, leafIndex);
788 if (leafIndex != oc.nLeaves())
792 "octree::const_iterator::const_iterator"
795 << "Traversal of tree returns : " << leafIndex << endl
796 << "Statistics of octree say : " << oc.nLeaves() << endl
797 << abort(FatalError);
803 template <class Type>
804 void Foam::octree<Type>::const_iterator::operator=(const const_iterator& iter)
806 if ((curLeaf_ < 0) && (iter.curLeaf_ >= 0))
810 "octree::const_iterator::operator="
811 "(const const_iterator&)"
813 << "lhs : " << curLeaf_ << endl
814 << "rhs : " << iter.curLeaf_ << endl
815 << abort(FatalError);
817 curLeaf_ = iter.curLeaf_;
818 curLeaf_ = iter.curLeaf_;
822 template <class Type>
823 bool Foam::octree<Type>::const_iterator::operator==
825 const const_iterator& iter
829 (curLeaf_ >= 0 ? curLeaf_ : octree_.nLeaves());
831 (iter.curLeaf_ >= 0 ? iter.curLeaf_ : iter.octree_.nLeaves());
833 return index1 == index2;
837 template <class Type>
838 bool Foam::octree<Type>::const_iterator::operator!=
840 const const_iterator& iter
843 return !(const_iterator::operator==(iter));
847 template <class Type>
848 const Foam::treeLeaf<Type>& Foam::octree<Type>::const_iterator::operator*()
850 return *leaves_[curLeaf_];
854 template <class Type>
855 typename Foam::octree<Type>::const_iterator&
856 Foam::octree<Type>::const_iterator::operator++()
863 template <class Type>
864 typename Foam::octree<Type>::const_iterator
865 Foam::octree<Type>::const_iterator::operator++(int)
867 const_iterator tmp = *this;
873 template <class Type>
874 typename Foam::octree<Type>::const_iterator
875 Foam::octree<Type>::begin() const
877 return const_iterator(*this, 0);
881 template <class Type>
882 typename Foam::octree<Type>::const_iterator
883 Foam::octree<Type>::cbegin() const
885 return const_iterator(*this, 0);
889 template <class Type>
890 const typename Foam::octree<Type>::const_iterator&
891 Foam::octree<Type>::end() const
893 return octree<Type>::endConstIter_;
897 template <class Type>
898 const typename Foam::octree<Type>::const_iterator&
899 Foam::octree<Type>::cend() const
901 return octree<Type>::endConstIter_;
905 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
907 template <class Type>
908 Foam::Ostream& Foam::operator<<(Ostream& os, const octree<Type>& oc)
910 return os << token::BEGIN_LIST
911 //<< token::SPACE << oc.shapes_
912 << token::SPACE << oc.octreeBb_
913 << token::SPACE << oc.maxLeafRatio_
914 << token::SPACE << oc.maxShapeRatio_
915 << token::SPACE << oc.minNLevels_
916 << token::SPACE << oc.deepestLevel_
917 << token::SPACE << oc.nEntries_
918 << token::SPACE << oc.nNodes_
919 << token::SPACE << oc.nLeaves_
920 << token::SPACE << *oc.topNode_
921 << token::SPACE << token::END_LIST;
925 // ************************************************************************* //