ENH: split off template-invariant part of indexedOctree node indexing

- code reduction, reinherit for dynamicIndexedOctree

ENH: additional OBJ writing, statistics
This commit is contained in:
Mark Olesen
2022-10-13 11:23:35 +02:00
committed by Andrew Heather
parent e5006a62d7
commit 3384747f9b
11 changed files with 692 additions and 569 deletions

View File

@ -820,12 +820,14 @@ $(interpolationWeights)/linearInterpolationWeights/linearInterpolationWeights.C
$(interpolationWeights)/splineInterpolationWeights/splineInterpolationWeights.C $(interpolationWeights)/splineInterpolationWeights/splineInterpolationWeights.C
algorithms/indexedOctree/indexedOctreeName.C algorithms/AABBTree/AABBTreeBase.C
algorithms/indexedOctree/indexedOctreeBase.C
algorithms/indexedOctree/treeDataCell.C algorithms/indexedOctree/treeDataCell.C
algorithms/indexedOctree/treeDataEdge.C algorithms/indexedOctree/treeDataEdge.C
algorithms/indexedOctree/treeDataPoint.C algorithms/indexedOctree/treeDataPoint.C
algorithms/dynamicIndexedOctree/dynamicIndexedOctreeName.C algorithms/dynamicIndexedOctree/dynamicIndexedOctreeBase.C
algorithms/dynamicIndexedOctree/dynamicTreeDataPoint.C algorithms/dynamicIndexedOctree/dynamicTreeDataPoint.C
parallel/commSchedule/commSchedule.C parallel/commSchedule/commSchedule.C

View File

@ -29,51 +29,8 @@ License
#include "AABBTree.H" #include "AABBTree.H"
#include "bitSet.H" #include "bitSet.H"
template<class Type>
Foam::scalar Foam::AABBTree<Type>::tolerance_ = 1e-4;
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * // // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
template<class Type>
void Foam::AABBTree<Type>::writeOBJ
(
const bool writeLinesOnly,
const treeBoundBox& bb,
label& vertI,
Ostream& os
) const
{
const pointField pts(bb.points());
for (const point& p : pts)
{
os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
}
if (writeLinesOnly)
{
for (const edge& e : treeBoundBox::edges)
{
os << "l " << e[0] + vertI + 1 << ' ' << e[1] + vertI + 1 << nl;
}
}
else
{
for (const face& f : treeBoundBox::faces)
{
os << 'f';
for (const label fpi : f)
{
os << ' ' << fpi + vertI + 1;
}
os << nl;
}
}
vertI += pts.size();
}
template<class Type> template<class Type>
void Foam::AABBTree<Type>::writeOBJ void Foam::AABBTree<Type>::writeOBJ
( (
@ -89,7 +46,7 @@ void Foam::AABBTree<Type>::writeOBJ
{ {
if (!leavesOnly || nodeI < 0) if (!leavesOnly || nodeI < 0)
{ {
writeOBJ(writeLinesOnly, bb, vertI, os); AABBTreeBase::writeOBJ(os, bb, vertI, writeLinesOnly);
} }
// recurse to find leaves // recurse to find leaves
@ -126,9 +83,9 @@ void Foam::AABBTree<Type>::createBoxes
( (
const bool equalBinSize, const bool equalBinSize,
const label level, const label level,
const List<Type>& objects, const UList<Type>& objects,
const pointField& points, const pointField& points,
const DynamicList<label>& objectIDs, const labelUList& objectIDs,
const treeBoundBox& bb, const treeBoundBox& bb,
const label nodeI, const label nodeI,
@ -153,7 +110,7 @@ void Foam::AABBTree<Type>::createBoxes
} }
scalar divide; scalar pivotValue;
if (equalBinSize) if (equalBinSize)
{ {
@ -179,17 +136,17 @@ void Foam::AABBTree<Type>::createBoxes
Foam::sort(component); Foam::sort(component);
divide = component[component.size()/2]; pivotValue = component[component.size()/2];
} }
else else
{ {
// Geometric middle // Geometric middle
divide = bb.min()[maxDir] + 0.5*maxSpan; pivotValue = bb.min()[maxDir] + 0.5*maxSpan;
} }
scalar divMin = divide + tolerance_*maxSpan; const scalar divMin = pivotValue + tolerance_*maxSpan;
scalar divMax = divide - tolerance_*maxSpan; const scalar divMax = pivotValue - tolerance_*maxSpan;
// Assign the objects to min or max bin // Assign the objects to min or max bin
@ -333,8 +290,8 @@ Foam::AABBTree<Type>::AABBTree
const UList<Type>& objects, const UList<Type>& objects,
const pointField& points, const pointField& points,
const bool equalBinSize, const bool equalBinSize,
const label maxLevel, label maxLevel,
const label minLeafSize label minLeafSize
) )
: :
maxLevel_(maxLevel), maxLevel_(maxLevel),
@ -356,7 +313,7 @@ Foam::AABBTree<Type>::AABBTree
treeBoundBox topBb(points); treeBoundBox topBb(points);
topBb.inflate(0.01); topBb.inflate(0.01);
DynamicList<label> objectIDs(identity(objects.size())); labelList objectIDs(identity(objects.size()));
createBoxes createBoxes
( (
@ -438,16 +395,15 @@ Foam::AABBTree<Type>::AABBTree
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> template<class Type>
const Foam::List<Foam::treeBoundBox>& Foam::AABBTree<Type>::boundBoxes() const void Foam::AABBTree<Type>::writeOBJ(Ostream& os) const
{ {
return boundBoxes_; label vertIndex(0);
}
for (const treeBoundBox& bb : boundBoxes_)
template<class Type> {
const Foam::List<Foam::labelList>& Foam::AABBTree<Type>::addressing() const // writeLinesOnly=false
{ AABBTreeBase::writeOBJ(os, bb, vertIndex, false);
return addressing_; }
} }
@ -486,24 +442,7 @@ bool Foam::AABBTree<Type>::overlaps(const boundBox& bbIn) const
template<class Type> template<class Type>
Foam::Ostream& Foam::operator<<(Ostream& os, const AABBTree<Type>& tree) Foam::Ostream& Foam::operator<<(Ostream& os, const AABBTree<Type>& tree)
{ {
if (os.format() == IOstreamOption::ASCII) os << tree.boundBoxes_ << tree.addressing_;
{
os << tree.maxLevel_ << token::SPACE
<< tree.minLeafSize_ << token::SPACE
<< tree.boundBoxes_ << token::SPACE
<< tree.addressing_ << token::SPACE;
}
else
{
os.write
(
reinterpret_cast<const char*>(&tree.maxLevel_),
sizeof(tree.maxLevel_)
+ sizeof(tree.minLeafSize_)
);
os << tree.boundBoxes_
<< tree.addressing_;
}
os.check(FUNCTION_NAME); os.check(FUNCTION_NAME);
return os; return os;
@ -513,23 +452,7 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const AABBTree<Type>& tree)
template<class Type> template<class Type>
Foam::Istream& Foam::operator>>(Istream& is, AABBTree<Type>& tree) Foam::Istream& Foam::operator>>(Istream& is, AABBTree<Type>& tree)
{ {
if (is.format() == IOstreamOption::ASCII) is >> tree.boundBoxes_ >> tree.addressing_;
{
is >> tree.maxLevel_
>> tree.minLeafSize_;
}
else
{
is.beginRawRead();
readRawLabel(is, &tree.maxLevel_);
readRawLabel(is, &tree.minLeafSize_);
is.endRawRead();
}
is >> tree.boundBoxes_
>> tree.addressing_;
is.check(FUNCTION_NAME); is.check(FUNCTION_NAME);
return is; return is;

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -36,11 +37,12 @@ Description
SourceFiles SourceFiles
AABBTree.C AABBTree.C
AABBTreeBase.C
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef AABBTree_H #ifndef Foam_AABBTree_H
#define AABBTree_H #define Foam_AABBTree_H
#include "labelList.H" #include "labelList.H"
#include "labelPair.H" #include "labelPair.H"
@ -54,10 +56,8 @@ SourceFiles
namespace Foam namespace Foam
{ {
// Forward declaration of friend functions and operators // Forward Declarations
template<class Type> class AABBTree;
template<class Type>
class AABBTree;
template<class Type> template<class Type>
Istream& operator>>(Istream&, AABBTree<Type>&); Istream& operator>>(Istream&, AABBTree<Type>&);
@ -65,21 +65,56 @@ Istream& operator>>(Istream&, AABBTree<Type>&);
template<class Type> template<class Type>
Ostream& operator<<(Ostream&, const AABBTree<Type>&); Ostream& operator<<(Ostream&, const AABBTree<Type>&);
/*---------------------------------------------------------------------------*\
Class AABBTreeBase Declaration
\*---------------------------------------------------------------------------*/
//- Template invariant parts for AABBTree
class AABBTreeBase
{
protected:
// Static Data
//- Relative tolerance.
static scalar tolerance_;
public:
// Constructors
//- Default construct
AABBTreeBase() = default;
// Output Helpers
//- Write treeBoundBox in OBJ format
static void writeOBJ
(
Ostream& os,
const treeBoundBox& bb,
label& vertIndex,
const bool writeLinesOnly = false
);
};
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class AABBTree Declaration Class AABBTree Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
template<class Type> template<class Type>
class AABBTree class AABBTree
:
public AABBTreeBase
{ {
protected: protected:
// Protected Data // Protected Data
//- Tolerance
static scalar tolerance_;
//- Maximum tree level //- Maximum tree level
label maxLevel_; label maxLevel_;
@ -95,15 +130,6 @@ protected:
// Protected Member Functions // Protected Member Functions
//- Write OBJ file of bounding box
void writeOBJ
(
const bool writeLinesOnly,
const treeBoundBox& bb,
label& vertI,
Ostream& os
) const;
//- Write OBJ for all bounding boxes //- Write OBJ for all bounding boxes
void writeOBJ void writeOBJ
( (
@ -122,9 +148,9 @@ protected:
( (
const bool equalBinSize, const bool equalBinSize,
const label level, const label level,
const List<Type>& objects, const UList<Type>& objects,
const pointField& points, const pointField& points,
const DynamicList<label>& objectIDs, const labelUList& objectIDs,
const treeBoundBox& bb, const treeBoundBox& bb,
const label nodeI, const label nodeI,
@ -138,7 +164,7 @@ public:
// Constructors // Constructors
//- Null constructor //- Default construct
AABBTree(); AABBTree();
//- Construct from components //- Construct from components
@ -148,8 +174,8 @@ public:
const UList<Type>& objects, const UList<Type>& objects,
const pointField& points, const pointField& points,
const bool equalBinSize = true, const bool equalBinSize = true,
const label maxLevel = 3, label maxLevel = 3,
const label minBinSize = 100 label minBinSize = 100
); );
@ -158,10 +184,16 @@ public:
// Access // Access
//- Return the bounding boxes making up the tree //- Return the bounding boxes making up the tree
const List<treeBoundBox>& boundBoxes() const; const List<treeBoundBox>& boundBoxes() const noexcept
{
return boundBoxes_;
}
//- Return the contents addressing //- Return the contents addressing
const List<labelList>& addressing() const; const List<labelList>& addressing() const noexcept
{
return addressing_;
}
// Evaluation // Evaluation
@ -169,12 +201,17 @@ public:
//- Determine whether a point is inside the bounding boxes //- Determine whether a point is inside the bounding boxes
bool pointInside(const point& pt) const; bool pointInside(const point& pt) const;
//- Determine whether a bounding box overlaps the tree bounding //- Determine whether a bounding box overlaps the tree bounding boxes
//- boxes
bool overlaps(const boundBox& bbIn) const; bool overlaps(const boundBox& bbIn) const;
// IOstream operators // Write
//- Write all tree boxes (leaves) in OBJ format
void writeOBJ(Ostream& os) const;
// IOstream Operators
friend Istream& operator>> <Type>(Istream&, AABBTree&); friend Istream& operator>> <Type>(Istream&, AABBTree&);
friend Ostream& operator<< <Type>(Ostream&, const AABBTree&); friend Ostream& operator<< <Type>(Ostream&, const AABBTree&);

View File

@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "AABBTree.H"
#include "treeBoundBox.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
Foam::scalar Foam::AABBTreeBase::tolerance_ = 1e-4;
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::AABBTreeBase::writeOBJ
(
Ostream& os,
const treeBoundBox& bb,
label& vertIndex,
const bool writeLinesOnly
)
{
// Annotate with '#box' which can be grep'd for later
os << "#box" << nl;
pointField pts(bb.points());
for (const point& p : pts)
{
os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
}
if (writeLinesOnly)
{
for (const edge& e : treeBoundBox::edges)
{
os << "l " << e[0] + vertIndex + 1
<< ' ' << e[1] + vertIndex + 1 << nl;
}
}
else
{
for (const face& f : treeBoundBox::faces)
{
os << 'f';
for (const label fpi : f)
{
os << ' ' << fpi + vertIndex + 1;
}
os << nl;
}
}
vertIndex += pts.size();
}
// ************************************************************************* //

View File

@ -179,7 +179,7 @@ void Foam::dynamicIndexedOctree<Type>::divide
template<class Type> template<class Type>
typename Foam::dynamicIndexedOctree<Type>::node Foam::dynamicIndexedOctreeBase::node
Foam::dynamicIndexedOctree<Type>::divide Foam::dynamicIndexedOctree<Type>::divide
( (
const treeBoundBox& bb, const treeBoundBox& bb,
@ -295,9 +295,9 @@ void Foam::dynamicIndexedOctree<Type>::recursiveSubDivision
// Recursively divide the contents until maxLevels_ is // Recursively divide the contents until maxLevels_ is
// reached or the content sizes are less than minSize_ // reached or the content sizes are less than minSize_
for (direction subOct = 0; subOct < 8; subOct++) for (direction subOct = 0; subOct < node::nChildren; ++subOct)
{ {
const labelBits& subNodeLabel = nod.subNodes_[subOct]; const labelBits subNodeLabel = nod.subNodes_[subOct];
if (isContent(subNodeLabel)) if (isContent(subNodeLabel))
{ {
@ -335,7 +335,7 @@ Foam::volumeType Foam::dynamicIndexedOctree<Type>::calcVolumeType
volumeType myType = volumeType::UNKNOWN; volumeType myType = volumeType::UNKNOWN;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
volumeType subType; volumeType subType;
@ -1027,7 +1027,7 @@ bool Foam::dynamicIndexedOctree<Type>::walkToParent
// Find octant nodeI is in. // Find octant nodeI is in.
parentOctant = 255; parentOctant = 255;
for (direction i = 0; i < parentNode.subNodes_.size(); i++) for (direction i = 0; i < node::nChildren; ++i)
{ {
labelBits index = parentNode.subNodes_[i]; labelBits index = parentNode.subNodes_[i];
@ -1794,7 +1794,7 @@ void Foam::dynamicIndexedOctree<Type>::findBox
const node& nod = nodes_[nodeI]; const node& nod = nodes_[nodeI];
const treeBoundBox& nodeBb = nod.bb_; const treeBoundBox& nodeBb = nod.bb_;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
labelBits index = nod.subNodes_[octant]; labelBits index = nod.subNodes_[octant];
@ -1842,7 +1842,7 @@ void Foam::dynamicIndexedOctree<Type>::findSphere
const node& nod = nodes_[nodeI]; const node& nod = nodes_[nodeI];
const treeBoundBox& nodeBb = nod.bb_; const treeBoundBox& nodeBb = nod.bb_;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
labelBits index = nod.subNodes_[octant]; labelBits index = nod.subNodes_[octant];
@ -1910,7 +1910,7 @@ void Foam::dynamicIndexedOctree<Type>::findNear
{ {
const node& nod2 = tree2.nodes()[tree2.getNode(index2)]; const node& nod2 = tree2.nodes()[tree2.getNode(index2)];
for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++) for (direction i2 = 0; i2 < node::nChildren; ++i2)
{ {
labelBits subIndex2 = nod2.subNodes_[i2]; labelBits subIndex2 = nod2.subNodes_[i2];
const treeBoundBox subBb2 const treeBoundBox subBb2
@ -1938,7 +1938,7 @@ void Foam::dynamicIndexedOctree<Type>::findNear
else if (tree2.isContent(index2)) else if (tree2.isContent(index2))
{ {
// index2 is leaf, index1 not yet. // index2 is leaf, index1 not yet.
for (direction i1 = 0; i1 < nod1.subNodes_.size(); i1++) for (direction i1 = 0; i1 < node::nChildren; ++i1)
{ {
labelBits subIndex1 = nod1.subNodes_[i1]; labelBits subIndex1 = nod1.subNodes_[i1];
const treeBoundBox subBb1 const treeBoundBox subBb1
@ -1978,7 +1978,7 @@ void Foam::dynamicIndexedOctree<Type>::findNear
if (bb2.overlaps(searchBox)) if (bb2.overlaps(searchBox))
{ {
for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++) for (direction i2 = 0; i2 < node::nChildren; ++i2)
{ {
labelBits subIndex2 = nod2.subNodes_[i2]; labelBits subIndex2 = nod2.subNodes_[i2];
const treeBoundBox subBb2 const treeBoundBox subBb2
@ -2067,7 +2067,7 @@ Foam::label Foam::dynamicIndexedOctree<Type>::countElements
const node& nod = nodes_[nodeI]; const node& nod = nodes_[nodeI];
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
nElems += countElements(nod.subNodes_[octant]); nElems += countElements(nod.subNodes_[octant]);
} }
@ -2085,6 +2085,43 @@ Foam::label Foam::dynamicIndexedOctree<Type>::countElements
} }
template<class Type>
void Foam::dynamicIndexedOctree<Type>::writeOBJ
(
const label nodeI,
Ostream& os,
label& vertIndex,
const bool leavesOnly,
const bool writeLinesOnly
) const
{
const node& nod = nodes_[nodeI];
const treeBoundBox& bb = nod.bb_;
for (direction octant = 0; octant < node::nChildren; ++octant)
{
const treeBoundBox subBb(bb.subBbox(octant));
labelBits index = nod.subNodes_[octant];
if (isNode(index))
{
label subNodeI = getNode(index);
writeOBJ(subNodeI, os, vertIndex, leavesOnly, writeLinesOnly);
}
else if (isContent(index))
{
indexedOctreeBase::writeOBJ(os, subBb, vertIndex, writeLinesOnly);
}
else if (isEmpty(index) && !leavesOnly)
{
indexedOctreeBase::writeOBJ(os, subBb, vertIndex, writeLinesOnly);
}
}
}
template<class Type> template<class Type>
void Foam::dynamicIndexedOctree<Type>::writeOBJ void Foam::dynamicIndexedOctree<Type>::writeOBJ
( (
@ -2092,11 +2129,6 @@ void Foam::dynamicIndexedOctree<Type>::writeOBJ
const direction octant const direction octant
) const ) const
{ {
OFstream str
(
"node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
);
labelBits index = nodes_[nodeI].subNodes_[octant]; labelBits index = nodes_[nodeI].subNodes_[octant];
treeBoundBox subBb; treeBoundBox subBb;
@ -2110,24 +2142,28 @@ void Foam::dynamicIndexedOctree<Type>::writeOBJ
subBb = nodes_[nodeI].bb_.subBbox(octant); subBb = nodes_[nodeI].bb_.subBbox(octant);
} }
OFstream os
(
"node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
);
Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
<< " to " << str.name() << endl; << " to " << os.name() << endl;
// Dump bounding box bool writeLinesOnly(false);
pointField bbPoints(subBb.points()); label vertIndex(0);
indexedOctreeBase::writeOBJ(os, subBb, vertIndex, writeLinesOnly);
}
forAll(bbPoints, i)
template<class Type>
void Foam::dynamicIndexedOctree<Type>::writeOBJ(Ostream& os) const
{
if (!nodes_.empty())
{ {
const point& pt = bbPoints[i]; label vertIndex(0);
// leavesOnly=true, writeLinesOnly=false
str<< "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl; writeOBJ(0, os, vertIndex, true, false);
}
forAll(treeBoundBox::edges, i)
{
const edge& e = treeBoundBox::edges[i];
str<< "l " << e[0] + 1 << ' ' << e[1] + 1 << nl;
} }
} }
@ -2456,7 +2492,7 @@ Foam::volumeType Foam::dynamicIndexedOctree<Type>::getVolumeType
} }
} }
Pout<< "dynamicIndexedOctree<Type>::getVolumeType : " Pout<< "dynamicIndexedOctree::getVolumeType : "
<< " bb:" << bb() << " bb:" << bb()
<< " nodes_:" << nodes_.size() << " nodes_:" << nodes_.size()
<< " nodeTypes_:" << nodeTypes_.size() << " nodeTypes_:" << nodeTypes_.size()
@ -2552,9 +2588,9 @@ bool Foam::dynamicIndexedOctree<Type>::insertIndex
{ {
bool shapeInserted = false; bool shapeInserted = false;
for (direction octant = 0; octant < 8; octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
const labelBits& subNodeLabel = nodes_[nodIndex].subNodes_[octant]; const labelBits subNodeLabel = nodes_[nodIndex].subNodes_[octant];
if (isNode(subNodeLabel)) if (isNode(subNodeLabel))
{ {
@ -2642,9 +2678,9 @@ Foam::label Foam::dynamicIndexedOctree<Type>::removeIndex
{ {
label totalContents = 0; label totalContents = 0;
for (direction octant = 0; octant < 8; octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
const labelBits& subNodeLabel = nodes_[nodIndex].subNodes_[octant]; const labelBits subNodeLabel = nodes_[nodIndex].subNodes_[octant];
if (isNode(subNodeLabel)) if (isNode(subNodeLabel))
{ {
@ -2731,7 +2767,7 @@ void Foam::dynamicIndexedOctree<Type>::print
<< "parent:" << nod.parent_ << nl << "parent:" << nod.parent_ << nl
<< "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl; << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
const treeBoundBox subBb(bb.subBbox(octant)); const treeBoundBox subBb(bb.subBbox(octant));
@ -2798,7 +2834,7 @@ void Foam::dynamicIndexedOctree<Type>::writeTreeInfo() const
nEntries += contents_[i]->size(); nEntries += contents_[i]->size();
} }
Pout<< "indexedOctree<Type>::indexedOctree" Pout<< "indexedOctree::indexedOctree"
<< " : finished construction of tree of:" << shapes().typeName << " : finished construction of tree of:" << shapes().typeName
<< nl << nl
<< " bounding box: " << this->bb() << nl << " bounding box: " << this->bb() << nl

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -38,14 +39,8 @@ SourceFiles
#ifndef Foam_dynamicIndexedOctree_H #ifndef Foam_dynamicIndexedOctree_H
#define Foam_dynamicIndexedOctree_H #define Foam_dynamicIndexedOctree_H
#include "treeBoundBox.H" #include "indexedOctree.H"
#include "pointIndexHit.H" #include "DynamicList.H"
#include "FixedList.H"
#include "Ostream.H"
#include "HashSet.H"
#include "labelBits.H"
#include "PackedList.H"
#include "volumeType.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -55,22 +50,36 @@ namespace Foam
typedef DynamicList<autoPtr<DynamicList<label>>> contentListList; typedef DynamicList<autoPtr<DynamicList<label>>> contentListList;
// Forward Declarations // Forward Declarations
template<class Type> class dynamicIndexedOctree;
template<class Type> Ostream& operator<<
(
Ostream&,
const dynamicIndexedOctree<Type>&
);
class Istream; class Istream;
template<class Type> class dynamicIndexedOctree;
template<class Type>
Ostream& operator<<(Ostream&, const dynamicIndexedOctree<Type>&);
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class dynamicIndexedOctreeName Declaration Class dynamicIndexedOctreeBase Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
TemplateName(dynamicIndexedOctree); //- Template invariant parts for dynamicIndexedOctree
// Same type of node bookkeeping as indexedOctree
class dynamicIndexedOctreeBase
:
public indexedOctreeBase
{
public:
//- Document that we are using the same types of node
using node = indexedOctreeBase::node;
//- Runtime type information
ClassName("dynamicIndexedOctree");
// Constructors
//- Default construct
dynamicIndexedOctreeBase() = default;
};
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
@ -80,54 +89,8 @@ TemplateName(dynamicIndexedOctree);
template<class Type> template<class Type>
class dynamicIndexedOctree class dynamicIndexedOctree
: :
public dynamicIndexedOctreeName public dynamicIndexedOctreeBase
{ {
public:
// Data types
//- Tree node. Has up pointer and down pointers.
class node
{
public:
//- Bounding box of this node
treeBoundBox bb_;
//- Parent node (index into nodes_ of tree)
label parent_;
//- IDs of the 8 nodes on all sides of the mid point
FixedList<labelBits, 8> subNodes_;
friend Ostream& operator<< (Ostream& os, const node& n)
{
return os << n.bb_ << token::SPACE
<< n.parent_ << token::SPACE << n.subNodes_;
}
friend Istream& operator>> (Istream& is, node& n)
{
return is >> n.bb_ >> n.parent_ >> n.subNodes_;
}
friend bool operator==(const node& a, const node& b)
{
return
a.bb_ == b.bb_
&& a.parent_ == b.parent_
&& a.subNodes_ == b.subNodes_;
}
friend bool operator!=(const node& a, const node& b)
{
return !(a == b);
}
};
private:
// Static data // Static data
//- Relative perturbation tolerance. Determines when point is //- Relative perturbation tolerance. Determines when point is
@ -137,7 +100,7 @@ private:
static scalar perturbTol_; static scalar perturbTol_;
// Private data // Private Data
//- Underlying shapes for geometric queries. //- Underlying shapes for geometric queries.
const Type shapes_; const Type shapes_;
@ -366,37 +329,19 @@ private:
//- Count number of elements on this and sublevels //- Count number of elements on this and sublevels
label countElements(const labelBits index) const; label countElements(const labelBits index) const;
//- Write node treeBoundBoxes in OBJ format
void writeOBJ
(
const label nodeI,
Ostream& os,
label& vertIndex,
const bool leavesOnly,
const bool writeLinesOnly = false
) const;
//- Dump node+octant to an obj file //- Dump node+octant to an obj file
void writeOBJ(const label nodeI, const direction octant) const; void writeOBJ(const label nodeI, const direction octant) const;
//- From index into contents_ to subNodes_ entry
static labelBits contentPlusOctant
(
const label i,
const direction octant
)
{
return labelBits(-i - 1, octant);
}
//- From index into nodes_ to subNodes_ entry
static labelBits nodePlusOctant
(
const label i,
const direction octant
)
{
return labelBits(i + 1, octant);
}
//- From empty to subNodes_ entry
static labelBits emptyPlusOctant
(
const direction octant
)
{
return labelBits(0, octant);
}
public: public:
@ -429,24 +374,24 @@ public:
// Access // Access
//- Reference to shape //- Reference to shape
const Type& shapes() const const Type& shapes() const noexcept { return shapes_; }
{
return shapes_;
}
//- List of all nodes //- List of all nodes
const List<node>& nodes() const const List<node>& nodes() const noexcept { return nodes_; }
{
return nodes_;
}
//- List of all contents (referenced by those nodes that are //- List of all contents
// contents) //- (referenced by those nodes that are contents)
const contentListList& contents() const const contentListList& contents() const
{ {
return contents_; return contents_;
} }
//- Per node, per octant whether is fully inside/outside/mixed.
PackedList<2>& nodeTypes() const noexcept
{
return nodeTypes_;
}
//- Top bounding box //- Top bounding box
const treeBoundBox& bb() const const treeBoundBox& bb() const
{ {
@ -458,49 +403,6 @@ public:
} }
// Conversions for entries in subNodes_.
static bool isContent(const labelBits i)
{
return i.val() < 0;
}
static bool isEmpty(const labelBits i)
{
return i.val() == 0;
}
static bool isNode(const labelBits i)
{
return i.val() > 0;
}
static label getContent(const labelBits i)
{
if (!isContent(i))
{
FatalErrorInFunction
<< abort(FatalError);
}
return -i.val()-1;
}
static label getNode(const labelBits i)
{
if (!isNode(i))
{
FatalErrorInFunction
<< abort(FatalError);
}
return i.val() - 1;
}
static direction getOctant(const labelBits i)
{
return i.bits();
}
// Queries // Queries
//- Calculate nearest point on nearest shape. //- Calculate nearest point on nearest shape.
@ -631,6 +533,9 @@ public:
// Write // Write
//- Write all tree boxes as OBJ format
void writeOBJ(Ostream& os) const;
//- Print tree. Either print all indices (printContent = true) or //- Print tree. Either print all indices (printContent = true) or
// just size of contents nodes. // just size of contents nodes.
void print void print

View File

@ -31,7 +31,7 @@ License
namespace Foam namespace Foam
{ {
defineTypeNameAndDebug(dynamicIndexedOctreeName, 0); defineTypeNameAndDebug(dynamicIndexedOctreeBase, 0);
} }

View File

@ -155,7 +155,7 @@ void Foam::indexedOctree<Type>::divide
template<class Type> template<class Type>
typename Foam::indexedOctree<Type>::node Foam::indexedOctreeBase::node
Foam::indexedOctree<Type>::divide Foam::indexedOctree<Type>::divide
( (
const treeBoundBox& bb, const treeBoundBox& bb,
@ -227,7 +227,7 @@ template<class Type>
void Foam::indexedOctree<Type>::splitNodes void Foam::indexedOctree<Type>::splitNodes
( (
const label minSize, const label minSize,
DynamicList<indexedOctree<Type>::node>& nodes, DynamicList<indexedOctreeBase::node>& nodes,
DynamicList<labelList>& contents DynamicList<labelList>& contents
) const ) const
{ {
@ -238,12 +238,7 @@ void Foam::indexedOctree<Type>::splitNodes
// moved so make sure not to keep any references! // moved so make sure not to keep any references!
for (label nodeI = 0; nodeI < currentSize; nodeI++) for (label nodeI = 0; nodeI < currentSize; nodeI++)
{ {
for for (direction octant = 0; octant < node::nChildren; ++octant)
(
direction octant = 0;
octant < nodes[nodeI].subNodes_.size();
octant++
)
{ {
labelBits index = nodes[nodeI].subNodes_[octant]; labelBits index = nodes[nodeI].subNodes_[octant];
@ -294,7 +289,7 @@ Foam::label Foam::indexedOctree<Type>::compactContents
if (level < compactLevel) if (level < compactLevel)
{ {
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
labelBits index = nod.subNodes_[octant]; labelBits index = nod.subNodes_[octant];
@ -316,7 +311,7 @@ Foam::label Foam::indexedOctree<Type>::compactContents
else if (level == compactLevel) else if (level == compactLevel)
{ {
// Compact all content on this level // Compact all content on this level
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
labelBits index = nod.subNodes_[octant]; labelBits index = nod.subNodes_[octant];
@ -356,7 +351,7 @@ Foam::volumeType Foam::indexedOctree<Type>::calcVolumeType
volumeType myType = volumeType::UNKNOWN; volumeType myType = volumeType::UNKNOWN;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
volumeType subType; volumeType subType;
@ -1048,7 +1043,7 @@ bool Foam::indexedOctree<Type>::walkToParent
// Find octant nodeI is in. // Find octant nodeI is in.
parentOctant = 255; parentOctant = 255;
for (direction i = 0; i < parentNode.subNodes_.size(); i++) for (direction i = 0; i < node::nChildren; ++i)
{ {
labelBits index = parentNode.subNodes_[i]; labelBits index = parentNode.subNodes_[i];
@ -1827,7 +1822,7 @@ void Foam::indexedOctree<Type>::findBox
const node& nod = nodes_[nodeI]; const node& nod = nodes_[nodeI];
const treeBoundBox& nodeBb = nod.bb_; const treeBoundBox& nodeBb = nod.bb_;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
labelBits index = nod.subNodes_[octant]; labelBits index = nod.subNodes_[octant];
@ -1875,7 +1870,7 @@ void Foam::indexedOctree<Type>::findSphere
const node& nod = nodes_[nodeI]; const node& nod = nodes_[nodeI];
const treeBoundBox& nodeBb = nod.bb_; const treeBoundBox& nodeBb = nod.bb_;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
labelBits index = nod.subNodes_[octant]; labelBits index = nod.subNodes_[octant];
@ -1943,7 +1938,7 @@ void Foam::indexedOctree<Type>::findNear
{ {
const node& nod2 = tree2.nodes()[tree2.getNode(index2)]; const node& nod2 = tree2.nodes()[tree2.getNode(index2)];
for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++) for (direction i2 = 0; i2 < node::nChildren; ++i2)
{ {
labelBits subIndex2 = nod2.subNodes_[i2]; labelBits subIndex2 = nod2.subNodes_[i2];
const treeBoundBox subBb2 const treeBoundBox subBb2
@ -1971,7 +1966,7 @@ void Foam::indexedOctree<Type>::findNear
else if (tree2.isContent(index2)) else if (tree2.isContent(index2))
{ {
// index2 is leaf, index1 not yet. // index2 is leaf, index1 not yet.
for (direction i1 = 0; i1 < nod1.subNodes_.size(); i1++) for (direction i1 = 0; i1 < node::nChildren; ++i1)
{ {
labelBits subIndex1 = nod1.subNodes_[i1]; labelBits subIndex1 = nod1.subNodes_[i1];
const treeBoundBox subBb1 const treeBoundBox subBb1
@ -2011,7 +2006,7 @@ void Foam::indexedOctree<Type>::findNear
if (bb2.overlaps(searchBox)) if (bb2.overlaps(searchBox))
{ {
for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++) for (direction i2 = 0; i2 < node::nChildren; ++i2)
{ {
labelBits subIndex2 = nod2.subNodes_[i2]; labelBits subIndex2 = nod2.subNodes_[i2];
const treeBoundBox subBb2 const treeBoundBox subBb2
@ -2100,7 +2095,7 @@ Foam::label Foam::indexedOctree<Type>::countElements
const node& nod = nodes_[nodeI]; const node& nod = nodes_[nodeI];
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
nElems += countElements(nod.subNodes_[octant]); nElems += countElements(nod.subNodes_[octant]);
} }
@ -2118,6 +2113,43 @@ Foam::label Foam::indexedOctree<Type>::countElements
} }
template<class Type>
void Foam::indexedOctree<Type>::writeOBJ
(
const label nodeI,
Ostream& os,
label& vertIndex,
const bool leavesOnly,
const bool writeLinesOnly
) const
{
const node& nod = nodes_[nodeI];
const treeBoundBox& bb = nod.bb_;
for (direction octant = 0; octant < node::nChildren; ++octant)
{
const treeBoundBox subBb(bb.subBbox(octant));
labelBits index = nod.subNodes_[octant];
if (isNode(index))
{
label subNodeI = getNode(index);
writeOBJ(subNodeI, os, vertIndex, leavesOnly, writeLinesOnly);
}
else if (isContent(index))
{
indexedOctreeBase::writeOBJ(os, subBb, vertIndex, writeLinesOnly);
}
else if (isEmpty(index) && !leavesOnly)
{
indexedOctreeBase::writeOBJ(os, subBb, vertIndex, writeLinesOnly);
}
}
}
template<class Type> template<class Type>
void Foam::indexedOctree<Type>::writeOBJ void Foam::indexedOctree<Type>::writeOBJ
( (
@ -2125,11 +2157,6 @@ void Foam::indexedOctree<Type>::writeOBJ
const direction octant const direction octant
) const ) const
{ {
OFstream str
(
"node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
);
labelBits index = nodes_[nodeI].subNodes_[octant]; labelBits index = nodes_[nodeI].subNodes_[octant];
treeBoundBox subBb; treeBoundBox subBb;
@ -2143,24 +2170,28 @@ void Foam::indexedOctree<Type>::writeOBJ
subBb = nodes_[nodeI].bb_.subBbox(octant); subBb = nodes_[nodeI].bb_.subBbox(octant);
} }
OFstream os
(
"node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
);
Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
<< " to " << str.name() << endl; << " to " << os.name() << endl;
// Dump bounding box bool writeLinesOnly(false);
pointField bbPoints(subBb.points()); label vertIndex(0);
indexedOctreeBase::writeOBJ(os, subBb, vertIndex, writeLinesOnly);
}
forAll(bbPoints, i)
template<class Type>
void Foam::indexedOctree<Type>::writeOBJ(Ostream& os) const
{
if (!nodes_.empty())
{ {
const point& pt = bbPoints[i]; label vertIndex(0);
// leavesOnly=true, writeLinesOnly=false
str<< "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl; writeOBJ(0, os, vertIndex, true, false);
}
forAll(treeBoundBox::edges, i)
{
const edge& e = treeBoundBox::edges[i];
str<< "l " << e[0] + 1 << ' ' << e[1] + 1 << nl;
} }
} }
@ -2210,7 +2241,7 @@ Foam::indexedOctree<Type>::indexedOctree
int oldMemSize = 0; int oldMemSize = 0;
if (debug) if (debug)
{ {
Pout<< "indexedOctree<Type>::indexedOctree:" << nl Pout<< "indexedOctree::indexedOctree:" << nl
<< " shapes:" << shapes.size() << nl << " shapes:" << shapes.size() << nl
<< " bb:" << bb << nl << " bb:" << bb << nl
<< endl; << endl;
@ -2241,24 +2272,28 @@ Foam::indexedOctree<Type>::indexedOctree
{ {
// Count number of references into shapes (i.e. contents) // Count number of references into shapes (i.e. contents)
label nEntries = 0; label nEntries = 0;
label minEntries = shapes.size();
label maxEntries = 0; label maxEntries = 0;
forAll(contents, i) for (const auto& subContents : contents)
{ {
maxEntries = max(maxEntries, contents[i].size()); const label num = subContents.size();
nEntries += contents[i].size();
nEntries += num;
minEntries = min(minEntries, num);
maxEntries = max(maxEntries, num);
} }
if (debug) if (debug)
{ {
Pout<< "indexedOctree<Type>::indexedOctree:" << nl Pout<< "indexedOctree::indexedOctree:" << nl
<< " nLevels:" << nLevels << nl << " nLevels:" << nLevels << nl
<< " nEntries per treeLeaf:" << nEntries/contents.size() << " nEntries:" << nEntries << nl
<< nl << " - min per leaf: " << minEntries << nl
<< " nEntries per shape (duplicity):" << " - max per leaf: " << maxEntries << nl
<< nEntries/shapes.size() << " - avg per leaf: "
<< nl << scalar(nEntries)/contents.size() << nl
<< " max nEntries:" << maxEntries << " - per shape (duplicity): "
<< nl << scalar(nEntries)/shapes_.size() << nl
<< endl; << endl;
} }
@ -2334,17 +2369,20 @@ Foam::indexedOctree<Type>::indexedOctree
if (debug) if (debug)
{ {
label nEntries = 0; label nEntries = 0;
label minEntries = shapes.size();
label maxEntries = 0; label maxEntries = 0;
forAll(contents_, i) for (const auto& subContents : contents_)
{ {
maxEntries = max(maxEntries, contents_[i].size()); const label num = subContents.size();
nEntries += contents_[i].size();
nEntries += num;
minEntries = min(minEntries, num);
maxEntries = max(maxEntries, num);
} }
label memSize = memInfo().size(); label memSize = memInfo().size();
Pout<< "indexedOctree::indexedOctree"
Pout<< "indexedOctree<Type>::indexedOctree"
<< " : finished construction of tree of:" << shapes.typeName << " : finished construction of tree of:" << shapes.typeName
<< nl << nl
<< " bb:" << this->bb() << nl << " bb:" << this->bb() << nl
@ -2352,13 +2390,13 @@ Foam::indexedOctree<Type>::indexedOctree
<< " nLevels:" << nLevels << nl << " nLevels:" << nLevels << nl
<< " treeNodes:" << nodes_.size() << nl << " treeNodes:" << nodes_.size() << nl
<< " nEntries:" << nEntries << nl << " nEntries:" << nEntries << nl
<< " per treeLeaf:" << " - min per leaf:" << minEntries << nl
<< " - max per leaf:" << maxEntries << nl
<< " - avg per leaf:"
<< scalar(nEntries)/contents.size() << nl << scalar(nEntries)/contents.size() << nl
<< " per shape (duplicity):" << " - per shape (duplicity):"
<< scalar(nEntries)/shapes.size() << nl << scalar(nEntries)/shapes.size() << nl
<< " max nEntries:" << maxEntries << " total memory:" << memSize-oldMemSize << nl
<< nl
<< " total memory:" << memSize-oldMemSize
<< endl; << endl;
} }
} }
@ -2740,7 +2778,7 @@ Foam::volumeType Foam::indexedOctree<Type>::getVolumeType
} }
} }
Pout<< "indexedOctree<Type>::getVolumeType : " Pout<< "indexedOctree::getVolumeType : "
<< " bb:" << bb() << " bb:" << bb()
<< " nodes_:" << nodes_.size() << " nodes_:" << nodes_.size()
<< " nodeTypes_:" << nodeTypes_.size() << " nodeTypes_:" << nodeTypes_.size()
@ -2803,7 +2841,7 @@ void Foam::indexedOctree<Type>::print
<< "parent:" << nod.parent_ << nl << "parent:" << nod.parent_ << nl
<< "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl; << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < node::nChildren; ++octant)
{ {
const treeBoundBox subBb(bb.subBbox(octant)); const treeBoundBox subBb(bb.subBbox(octant));

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -52,45 +53,61 @@ namespace Foam
{ {
// Forward Declarations // Forward Declarations
class Istream;
template<class Type> class indexedOctree; template<class Type> class indexedOctree;
template<class Type> Ostream& operator<<(Ostream&, const indexedOctree<Type>&); template<class Type> Ostream& operator<<(Ostream&, const indexedOctree<Type>&);
class Istream;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class indexedOctreeName Declaration Class indexedOctreeBase Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
TemplateName(indexedOctree); //- Template invariant parts for indexedOctree
// The internal node bookkeeping is encoded follows:
// - 0: empty
/*---------------------------------------------------------------------------*\ // - +ve: parent
Class indexedOctree Declaration // - -ve: leaf
\*---------------------------------------------------------------------------*/ class indexedOctreeBase
template<class Type>
class indexedOctree
:
public indexedOctreeName
{ {
public: public:
// Data types // Public Data Types
//- Tree node. Has up pointer and down pointers. //- Tree node. Has up pointer and down pointers.
class node class node
{ {
public: public:
//- Has exactly 8 sub-nodes (octants)
static constexpr direction nChildren = 8;
//- Bounding box of this node //- Bounding box of this node
treeBoundBox bb_; treeBoundBox bb_;
//- Parent node (index into nodes_ of tree) //- Parent node (index into flat list addressing for tree)
label parent_; label parent_ = -1;
//- IDs of the 8 nodes on all sides of the mid point //- IDs of the 8 nodes on all sides of the mid point
FixedList<labelBits, 8> subNodes_; FixedList<labelBits, 8> subNodes_;
// Operators
friend bool operator==(const node& a, const node& b)
{
return
(
a.parent_ == b.parent_
&& a.subNodes_ == b.subNodes_
&& a.bb_ == b.bb_
);
}
friend bool operator!=(const node& a, const node& b)
{
return !(a == b);
}
friend Ostream& operator<< (Ostream& os, const node& n) friend Ostream& operator<< (Ostream& os, const node& n)
{ {
return os << n.bb_ << token::SPACE return os << n.bb_ << token::SPACE
@ -101,24 +118,124 @@ public:
{ {
return is >> n.bb_ >> n.parent_ >> n.subNodes_; return is >> n.bb_ >> n.parent_ >> n.subNodes_;
} }
friend bool operator==(const node& a, const node& b)
{
return
a.bb_ == b.bb_
&& a.parent_ == b.parent_
&& a.subNodes_ == b.subNodes_;
}
friend bool operator!=(const node& a, const node& b)
{
return !(a == b);
}
}; };
private: // Static Functions
// Tests for node handling
// (0: empty, +ve: parent, -ve: leaf)
//- An empty node - no content
static bool isEmpty(labelBits i) noexcept
{
return (i.val() == 0);
}
//- Node with content (leaf)
static bool isContent(labelBits i) noexcept
{
return (i.val() < 0);
}
//- A parent node
static bool isNode(labelBits i) noexcept
{
return (i.val() > 0);
}
// Decode/retrieve node addressing
//- Return real (dereferenced) index for a content node
static label getContent(labelBits i)
{
if (!isContent(i))
{
FatalErrorInFunction
<< abort(FatalError);
}
return (-i.val()-1);
}
//- Return real (dereferenced) index for a parent node
static label getNode(const labelBits i)
{
if (!isNode(i))
{
FatalErrorInFunction
<< abort(FatalError);
}
return (i.val()-1);
}
//- Return sub-node direction/octant
static direction getOctant(labelBits i) noexcept
{
return i.bits();
}
protected:
// Protected Member Functions
// Encode node addressing
// (only used when building)
//- From empty to subNodes_ entry
static labelBits emptyPlusOctant(direction octant)
{
return labelBits(0, octant);
}
//- From index into contents_ to subNodes_ entry
static labelBits contentPlusOctant(label i, direction octant)
{
return labelBits(-i-1, octant);
}
//- From index into nodes_ to subNodes_ entry
static labelBits nodePlusOctant(label i, direction octant)
{
return labelBits(i+1, octant);
}
public:
//- Runtime type information
ClassName("indexedOctree");
// Constructors
//- Default construct
indexedOctreeBase() = default;
// Output Helpers
//- Write treeBoundBox in OBJ format
static void writeOBJ
(
Ostream& os,
const treeBoundBox& bb,
label& vertIndex,
const bool writeLinesOnly = false
);
};
/*---------------------------------------------------------------------------*\
Class indexedOctree Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class indexedOctree
:
public indexedOctreeBase
{
// Static data // Static data
//- Relative perturbation tolerance. Determines when point is //- Relative perturbation tolerance. Determines when point is
@ -128,7 +245,7 @@ private:
static scalar perturbTol_; static scalar perturbTol_;
// Private data // Private Data
//- Underlying shapes for geometric queries. //- Underlying shapes for geometric queries.
const Type shapes_; const Type shapes_;
@ -142,6 +259,7 @@ private:
//- Per node per octant whether is fully inside/outside/mixed. //- Per node per octant whether is fully inside/outside/mixed.
mutable PackedList<2> nodeTypes_; mutable PackedList<2> nodeTypes_;
// Private Member Functions // Private Member Functions
//- Helper: does bb intersect a sphere around sample? Or is any //- Helper: does bb intersect a sphere around sample? Or is any
@ -366,37 +484,19 @@ private:
//- Count number of elements on this and sublevels //- Count number of elements on this and sublevels
label countElements(const labelBits index) const; label countElements(const labelBits index) const;
//- Write node treeBoundBoxes in OBJ format
void writeOBJ
(
const label nodeI,
Ostream& os,
label& vertIndex,
const bool leavesOnly,
const bool writeLinesOnly = false
) const;
//- Dump node+octant to an obj file //- Dump node+octant to an obj file
void writeOBJ(const label nodeI, const direction octant) const; void writeOBJ(const label nodeI, const direction octant) const;
//- From index into contents_ to subNodes_ entry
static labelBits contentPlusOctant
(
const label i,
const direction octant
)
{
return labelBits(-i - 1, octant);
}
//- From index into nodes_ to subNodes_ entry
static labelBits nodePlusOctant
(
const label i,
const direction octant
)
{
return labelBits(i + 1, octant);
}
//- From empty to subNodes_ entry
static labelBits emptyPlusOctant
(
const direction octant
)
{
return labelBits(0, octant);
}
public: public:
@ -437,29 +537,30 @@ public:
return autoPtr<indexedOctree<Type>>::New(*this); return autoPtr<indexedOctree<Type>>::New(*this);
} }
// Member Functions // Member Functions
// Access // Access
//- Reference to shape //- Reference to shape
const Type& shapes() const const Type& shapes() const noexcept { return shapes_; }
{
return shapes_;
}
//- List of all nodes //- List of all nodes
const List<node>& nodes() const const List<node>& nodes() const noexcept { return nodes_; }
{
return nodes_;
}
//- List of all contents (referenced by those nodes that are //- List of all contents
// contents) //- (referenced by those nodes that are contents)
const labelListList& contents() const const List<labelList>& contents() const noexcept
{ {
return contents_; return contents_;
} }
//- Per node, per octant whether is fully inside/outside/mixed.
PackedList<2>& nodeTypes() const noexcept
{
return nodeTypes_;
}
//- Top bounding box //- Top bounding box
const treeBoundBox& bb() const const treeBoundBox& bb() const
{ {
@ -470,55 +571,6 @@ public:
return nodes_[0].bb_; return nodes_[0].bb_;
} }
//- Per node, per octant whether is fully inside/outside/mixed.
PackedList<2>& nodeTypes() const
{
return nodeTypes_;
}
// Conversions for entries in subNodes_.
static bool isContent(const labelBits i)
{
return i.val() < 0;
}
static bool isEmpty(const labelBits i)
{
return i.val() == 0;
}
static bool isNode(const labelBits i)
{
return i.val() > 0;
}
static label getContent(const labelBits i)
{
if (!isContent(i))
{
FatalErrorInFunction
<< abort(FatalError);
}
return -i.val()-1;
}
static label getNode(const labelBits i)
{
if (!isNode(i))
{
FatalErrorInFunction
<< abort(FatalError);
}
return i.val() - 1;
}
static direction getOctant(const labelBits i)
{
return i.bits();
}
// Queries // Queries
@ -672,6 +724,9 @@ public:
// Write // Write
//- Write (non-empty) tree boxes in OBJ format
void writeOBJ(Ostream& os) const;
//- Print tree. Either print all indices (printContent = true) or //- Print tree. Either print all indices (printContent = true) or
// just size of contents nodes. // just size of contents nodes.
void print void print

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,12 +27,58 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "indexedOctree.H" #include "indexedOctree.H"
#include "treeBoundBox.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam namespace Foam
{ {
defineTypeNameAndDebug(indexedOctreeName, 0); defineTypeNameAndDebug(indexedOctreeBase, 0);
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::indexedOctreeBase::writeOBJ
(
Ostream& os,
const treeBoundBox& bb,
label& vertIndex,
const bool writeLinesOnly
)
{
// Annotate with '#box' which can be grep'd for later
os << "#box" << nl;
pointField pts(bb.points());
for (const point& p : pts)
{
os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
}
if (writeLinesOnly)
{
for (const edge& e : treeBoundBox::edges)
{
os << "l " << e[0] + vertIndex + 1
<< ' ' << e[1] + vertIndex + 1 << nl;
}
}
else
{
for (const face& f : treeBoundBox::faces)
{
os << 'f';
for (const label fpi : f)
{
os << ' ' << fpi + vertIndex + 1;
}
os << nl;
}
}
vertIndex += pts.size();
} }

View File

@ -1517,7 +1517,7 @@ void Foam::distributedTriSurfaceMesh::collectLeafMids
DynamicField<point>& midPoints DynamicField<point>& midPoints
) const ) const
{ {
const indexedOctree<treeDataTriSurface>::node& nod = tree().nodes()[nodeI]; const auto& nod = tree().nodes()[nodeI];
for (direction octant = 0; octant < nod.subNodes_.size(); octant++) for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
{ {
@ -1557,7 +1557,7 @@ Foam::volumeType Foam::distributedTriSurfaceMesh::calcVolumeType
// Recurses to determine status of lowest level boxes. Level above is // Recurses to determine status of lowest level boxes. Level above is
// combination of octants below. // combination of octants below.
const indexedOctree<treeDataTriSurface>::node& nod = tree().nodes()[nodeI]; const auto& nod = tree().nodes()[nodeI];
volumeType myType = volumeType::UNKNOWN; volumeType myType = volumeType::UNKNOWN;
@ -1619,7 +1619,7 @@ Foam::volumeType Foam::distributedTriSurfaceMesh::cachedVolumeType
const point& sample const point& sample
) const ) const
{ {
const indexedOctree<treeDataTriSurface>::node& nod = tree().nodes()[nodeI]; const auto& nod = tree().nodes()[nodeI];
direction octant = nod.bb_.subOctant(sample); direction octant = nod.bb_.subOctant(sample);
@ -4141,10 +4141,9 @@ void Foam::distributedTriSurfaceMesh::getVolumeType
{ {
// Get local tree // Get local tree
const indexedOctree<treeDataTriSurface>& t = tree(); const indexedOctree<treeDataTriSurface>& t = tree();
const auto& nodes = t.nodes();
PackedList<2>& nt = t.nodeTypes(); PackedList<2>& nt = t.nodeTypes();
const List<indexedOctree<treeDataTriSurface>::node>& nodes = nt.resize(nodes.size());
t.nodes();
nt.setSize(nodes.size());
nt = volumeType::UNKNOWN; nt = volumeType::UNKNOWN;
// Collect midpoints // Collect midpoints