Files
openfoam/src/meshTools/octree/treeNode.C
2008-08-28 15:50:11 +01:00

1448 lines
37 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
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 2 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, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Description
\*---------------------------------------------------------------------------*/
#include "treeNode.H"
#include "octree.H"
#include "treeLeaf.H"
#include "treeBoundBox.H"
#include "long.H"
#include "linePointRef.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template <class Type>
const label treeNode<Type>::leafOffset = 100;
template <class Type>
const labelList treeNode<Type>::dummy(1);
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template <class Type>
void treeNode<Type>::setAsNode(const label octant)
{
subNodeTypes_ |= (0x1 << octant);
}
template <class Type>
void treeNode<Type>::setAsLeaf(const label octant)
{
subNodeTypes_ &= ~(0x1 << octant);
}
// Set pointer to sub node
template <class Type>
void treeNode<Type>::setNodePtr(const label octant, treeElem<Type>* treeNodePtr)
{
setAsNode(octant);
subNodes_[octant] = treeNodePtr;
}
// Set pointer to sub leaf
template <class Type>
void treeNode<Type>::setLeafPtr(const label octant, treeElem<Type>* treeLeafPtr)
{
setAsLeaf(octant);
subNodes_[octant] = treeLeafPtr;
}
template <class Type>
void treeNode<Type>::setVolType(const label octant, const label type)
{
if ((type < 0) || (type > 3))
{
FatalErrorIn("treeNode<Type>::setVolType(const label, const label)")
<< "Type " << type << " not within range 0..3" << endl;
}
// Clear out two bits at position 2*octant
volType_ &= ~(0x3 << 2*octant);
// Add the two bits of type
volType_ |= (type << 2*octant);
}
template <class Type>
void treeNode<Type>::space(Ostream& os, const label n)
{
for(label i=0; i<n; i++)
{
os<< ' ';
}
}
// look in single octant starting from <start>
template <class Type>
const treeLeaf<Type>* treeNode<Type>::findLeafLineOctant
(
const int level,
const Type& shapes,
const label octant,
const vector& direction,
point& start,
const point& end
) const
{
static const char* functionName =
"treeNode<Type>::findLeafLineOctant"
"(const int, const Type&, const label, const vector&,"
" point&, const point&)";
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLineOctant : bb:" << this->bb()
<< " start:" << start
<< " end:" << end
<< " mid:" << mid()
<< " Searching octant:" << octant
<< endl;
}
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node: recurse into subnodes
const treeNode<Type>* subNodePtr = getNodePtr(octant);
if (subNodePtr->bb().contains(direction, start))
{
// Search on lower level
const treeLeaf<Type>* subLeafPtr =
subNodePtr->findLeafLine
(
level + 1,
shapes,
start,
end
);
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLineOctant : bb:" << this->bb()
<< " returning from sub treeNode"
<< " with start:" << start << " subLeaf:"
<< long(subLeafPtr) << endl;
}
return subLeafPtr;
}
else
{
FatalErrorIn(functionName)
<< "Sub node " << subNodePtr->bb()
<< " at octant " << octant
<< " does not contain start " << start
<< abort(FatalError);
}
}
else
{
// Leaf
const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
if (subLeafPtr->bb().contains(direction, start))
{
// Step to end of subleaf bb
point tmp;
if
(
!subLeafPtr->bb().intersects
(
end,
start,
tmp
)
)
{
FatalErrorIn(functionName)
<< "Sub leaf contains start " << start
<< " but line does not intersect its bb "
<< subLeafPtr->bb()
<< abort(FatalError);
}
start = tmp;
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLineOctant : returning from intersecting"
<< " treeLeaf " << subLeafPtr->bb()
<< " with start:" << start << " subLeaf:"
<< long(subLeafPtr) << endl;
}
return subLeafPtr;
}
else
{
FatalErrorIn(functionName)
<< "Sub leaf " << subLeafPtr->bb()
<< " at octant " << octant
<< " does not contain start " << start
<< abort(FatalError);
}
}
}
else
{
// Empty subNode. Transfer across.
const treeBoundBox emptyBb = this->bb().subBbox(mid(), octant);
if (emptyBb.contains(direction, start))
{
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLineOctant : Empty node. Octant:" << octant
<< " start:" << start
<< " bb:" << this->bb()
<< " emptyBb:" << emptyBb << endl;
}
// Update start by clipping to emptyBb
point tmp;
if
(
!emptyBb.intersects
(
end,
start,
tmp
)
)
{
FatalErrorIn(functionName)
<< "Empty node contains start " << start
<< " but line does not intersect its (calculated)"
<< " bb " << emptyBb
<< endl << "This might be due to truncation error"
<< abort(FatalError);
}
start = tmp;
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLineOctant : returning from intersecting with"
<< " empty " << emptyBb
<< " with start:" << start << " subLeaf:" << 0 << endl;
}
return NULL;
}
else
{
FatalErrorIn(functionName)
<< "Empty node " << emptyBb
<< " at octant " << octant
<< " does not contain start " << start
<< abort(FatalError);
}
}
FatalErrorIn(functionName)
<< "Octant " << octant << " of cube " << this->bb()
<< " does not contain start " << start
<< abort(FatalError);
return NULL;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from components
template <class Type>
treeNode<Type>::treeNode(const treeBoundBox& bb)
:
treeElem<Type>(bb),
treeNodeName(),
mid_(bb.mid()),
subNodeTypes_(0),
volType_(0)
{
for(label octant=0; octant<8; octant++)
{
subNodes_[octant] = NULL;
setVolType(octant, octree<Type>::UNKNOWN);
}
}
// Construct from Istream
template <class Type>
treeNode<Type>::treeNode
(
Istream& is
)
{
is >> *this;
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template <class Type>
treeNode<Type>::~treeNode()
{
for(int octant=0; octant<8; octant++)
{
if (subNodes()[octant])
{
if (isNode(octant))
{
delete getNodePtr(octant);
}
else
{
delete getLeafPtr(octant);
}
}
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
// Distributes cells to subLeaves
template <class Type>
void treeNode<Type>::distribute
(
const label level,
octree<Type>& top,
const Type& shapes,
const labelList& indices
)
{
if (debug & 1)
{
space(Pout, level);
Pout<< "treeNode::distributing " << indices.size() << endl;
}
// Create subLeaves if nessecary
for(label octant=0; octant<8; octant++)
{
if (subNodes()[octant])
{
printNode(Pout, level);
FatalErrorIn
(
"treeNode<Type>::distribute(const label, octree<Type>&, "
"const Type&, const labelList&)"
) << "subNode already available at octant:" << octant
<< abort(FatalError);
}
else
{
treeLeaf<Type>* subLeafPtr =
new treeLeaf<Type>
(
this->bb().subBbox(mid(), octant),
indices.size()
);
top.setLeaves(top.nLeaves() + 1);
setLeafPtr(octant, subLeafPtr);
}
}
// add cells to correct sub leaf
forAll(indices, i)
{
const label shapei = indices[i];
for(label octant=0; octant<8; octant++)
{
treeLeaf<Type>* leafPtr = getLeafPtr(octant);
if (shapes.overlaps(shapei, leafPtr->bb()))
{
if (debug == 1)
{
space(Pout, level);
Pout<< "inserting " << shapei;
shapes.write(Pout, shapei);
Pout<< " into " << leafPtr->bb() << endl;
}
leafPtr->insert(shapei);
top.setEntries(top.nEntries() + 1);
}
}
}
// Trim size of subLeaves
for(label octant=0; octant<8; octant++)
{
treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
if (subLeafPtr->size() == 0)
{
// Contains no data. Delete.
setLeafPtr(octant, NULL);
delete subLeafPtr;
top.setLeaves(top.nLeaves() - 1);
}
else
{
// Trim to actual size.
subLeafPtr->trim();
}
}
if (debug & 1)
{
space(Pout, level);
Pout<< "end of treeNode::distribute" << endl;
}
}
// Descends to refineLevel and checks the subLeaves for redistribution
template <class Type>
void treeNode<Type>::redistribute
(
const label level,
octree<Type>& top,
const Type& shapes,
const label refineLevel
)
{
if (debug & 1)
{
space(Pout, level);
Pout<< "treeNode::redistribute with level:" << level
<< " refineLevel:" << refineLevel << endl;
}
// Descend to correct level
if (level < refineLevel)
{
for(label octant=0; octant<8; octant++)
{
if (subNodes()[octant])
{
if (isNode(octant))
{
getNodePtr(octant)->redistribute
(
level+1,
top,
shapes,
refineLevel
);
}
}
}
}
else
{
// Reached correct (should also be deepest) level of treeNode
if (debug & 1)
{
space(Pout, level);
Pout<< "treeNode::redistribute : now at correct level" << endl;
}
// handle redistribution of sub leaves
for(label octant=0; octant<8; octant++)
{
if (subNodes()[octant])
{
if (isNode(octant))
{
FatalErrorIn
(
"treeNode<Type>::redistribute(const int, octree& top,"
"const int, const treeBoundBox&)"
) << "found treeNode instead of treeLeaf" << endl
<< abort(FatalError);
}
else
{
treeLeaf<Type>* leafPtr = getLeafPtr(octant);
treeLeaf<Type>* newSubPtr = leafPtr->redistribute
(
level,
top,
shapes
);
if (newSubPtr && (newSubPtr != leafPtr))
{
// redistribute has created nodePtr
// so delete no longer used subPtr and update info
if (debug & 1)
{
Pout<< "deleting "
<< top.nEntries() - leafPtr->size()
<< " entries" << endl;
}
top.setEntries(top.nEntries() - leafPtr->size());
delete leafPtr;
top.setLeaves(top.nLeaves() - 1);
setNodePtr(octant, newSubPtr);
}
}
}
}
if (debug & 1)
{
space(Pout, level);
Pout<< "end of treeNode::redistribute for correct level" << endl;
}
}
if (debug & 1)
{
space(Pout, level);
Pout<< "return from treeNode::redistribute with bb:" << this->bb()
<< endl;
}
}
// Set type of node.
template <class Type>
label treeNode<Type>::setSubNodeType
(
const label level,
octree<Type>& top,
const Type& shapes
)
{
if (debug & 4)
{
space(Pout, level);
Pout<< "treeNode::setSubNodeType with level:" << level
<< " bb:" << this->bb() << endl;
}
label myType = -1;
for(label octant=0; octant<8; octant++)
{
label subType = -1;
if (subNodes()[octant])
{
if (isNode(octant))
{
subType = getNodePtr(octant)->setSubNodeType
(
level+1,
top,
shapes
);
}
else
{
subType = getLeafPtr(octant)->setSubNodeType
(
level+1,
top,
shapes
);
}
}
else
{
// No data in this one. Set type for octant acc. to its bounding
// box.
const treeBoundBox subBb = this->bb().subBbox(mid(), octant);
subType = shapes.getSampleType(top, subBb.mid());
}
if (debug & 4)
{
space(Pout, level);
Pout<< "treeNode::setSubNodeType : setting octant with bb:"
<< this->bb().subBbox(mid(), octant)
<< " to type:" << octree<Type>::volType(subType) << endl;
}
setVolType(octant, subType);
// Combine sub node types into type for treeNode. Result is 'mixed' if
// types differ among subnodes.
if (myType == -1)
{
myType = subType;
}
else if (subType != myType)
{
myType = octree<Type>::MIXED;
}
}
if (debug & 4)
{
space(Pout, level);
Pout<< "return from treeNode::setSubNodeType with type:"
<< octree<Type>::volType(myType)
<< " bb:" << this->bb() << endl;
}
return myType;
}
// Get type of node.
template <class Type>
label treeNode<Type>::getSampleType
(
const label level,
const octree<Type>& top,
const Type& shapes,
const point& sample
) const
{
if (debug & 4)
{
space(Pout, level);
Pout<< "treeNode::getSampleType with level:" << level
<< " bb:" << this->bb() << " sample:" << sample << endl;
}
// Determine octant of bb. If on edge just use whichever octant.
bool onEdge = false;
label octant = this->bb().subOctant(mid(), sample, onEdge);
label type = getVolType(octant);
if (type == octree<Type>::MIXED)
{
// At this level multiple sub types. Recurse to resolve.
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node: recurse into subnodes
type = getNodePtr(octant)->getSampleType
(
level + 1,
top,
shapes,
sample
);
}
else
{
// Leaf
type = getLeafPtr(octant)->getSampleType
(
level + 1,
top,
shapes,
sample
);
}
}
else
{
// Problem: empty subnode should have a type
FatalErrorIn
(
"treeNode<Type>::getSampleType"
"(const label, octree<Type>&, const Type&, const point&)"
) << "Empty node bb:" << this->bb().subBbox(mid(), octant)
<< " has non-mixed type:"
<< octree<Type>::volType(type)
<< abort(FatalError);
}
}
if (type == octree<Type>::MIXED)
{
FatalErrorIn
(
"treeNode<Type>::getSampleType"
"(const label, octree<Type>&, const Type&, const point&)"
) << "Type is MIXED when searching for " << sample
<< " at level " << this->bb() << endl
<< "This probably is because the octree has not been constructed"
<< " with search facility." << exit(FatalError);
}
if (debug & 4)
{
space(Pout, level);
Pout<< "return from treeNode::getSampleType with type:"
<< octree<Type>::volType(type)
<< " bb:" << this->bb()
<< " sample:" << sample << endl;
}
return type;
}
template <class Type>
label treeNode<Type>::find
(
const Type& shapes,
const point& sample
) const
{
// Find octant of sample. Don't care if on edge (since any item on edge
// will have been inserted in both subcubes)
bool onEdge = false;
label octant = this->bb().subOctant(mid(), sample, onEdge);
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node: recurse into subnodes
return getNodePtr(octant)->find
(
shapes,
sample
);
}
else
{
// Leaf: let leaf::find handle this
return getLeafPtr(octant)->find(shapes, sample);
}
}
return -1;
}
template <class Type>
bool treeNode<Type>::findTightest
(
const Type& shapes,
const point& sample,
treeBoundBox& tightest
) const
{
bool changed = false;
// Get best guess for starting octant
bool onEdge = false;
label sampleOctant = this->bb().subOctant(mid(), sample, onEdge);
// Go into all suboctants (one containing sample first) and update tightest.
// Order of visiting is if e.g. sampleOctant = 5:
// 5 1 2 3 4 0 6 7
for(label octanti=0; octanti<8; octanti++)
{
label octant;
if (octanti == 0)
{
// Use sampleOctant first
octant = sampleOctant;
}
else if (octanti == sampleOctant)
{
octant = 0;
}
else
{
octant = octanti;
}
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node: recurse into subnodes
const treeNode<Type>* subNodePtr = getNodePtr(octant);
if (subNodePtr->bb().overlaps(tightest))
{
// there might be a better fit inside this subNode
changed |=
subNodePtr->findTightest
(
shapes,
sample,
tightest
);
}
}
else
{
// Leaf: let leaf::find handle this
const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
if (subLeafPtr->bb().overlaps(tightest))
{
// there might be a better fit inside this subLeaf
changed |=
subLeafPtr->findTightest
(
shapes,
sample,
tightest
);
}
}
}
}
return changed;
}
template <class Type>
bool treeNode<Type>::findNearest
(
const Type& shapes,
const point& sample,
treeBoundBox& tightest,
label& tightesti,
scalar& tightestDist
) const
{
bool changed = false;
if (debug & 8)
{
Pout<< "In findNearest with sample:" << sample << " cube:"
<< this->bb() << " tightest:" << tightest << endl;
}
bool onEdge = false;
label sampleOctant = this->bb().subOctant(mid(), sample, onEdge);
// Go into all suboctants (one containing sample first) and update tightest.
// Order of visiting is if e.g. sampleOctant = 5:
// 5 1 2 3 4 0 6 7
for(label octanti=0; octanti<8; octanti++)
{
label octant;
if (octanti == 0)
{
// Use sampleOctant first
octant = sampleOctant;
}
else if (octanti == sampleOctant)
{
octant = 0;
}
else
{
octant = octanti;
}
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node
const treeNode<Type>* subNodePtr = getNodePtr(octant);
if (subNodePtr->bb().overlaps(tightest))
{
// there might be a better fit inside this subNode
changed |=
subNodePtr->findNearest
(
shapes,
sample,
tightest,
tightesti,
tightestDist
);
}
}
else
{
// Leaf: let leaf::find handle this
const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
if (subLeafPtr->bb().overlaps(tightest))
{
// there might be a better fit inside this subNode
changed |=
subLeafPtr->findNearest
(
shapes,
sample,
tightest,
tightesti,
tightestDist
);
}
}
}
}
if (debug & 8)
{
Pout<< "Exiting findNearest for sample:" << sample << " cube:"
<< this->bb() << " tightesti:" << tightesti << endl;
}
return changed;
}
template <class Type>
bool treeNode<Type>::findNearest
(
const Type& shapes,
const linePointRef& ln,
treeBoundBox& tightest,
label& tightesti,
point& linePoint, // nearest point on line
point& shapePoint // nearest point on shape
) const
{
bool changed = false;
bool onEdge = false;
// Estimate for where best to start searching
label sampleOctant = this->bb().subOctant(mid(), ln.centre(), onEdge);
// Go into all suboctants (one containing sample first) and update tightest.
// Order of visiting is if e.g. sampleOctant = 5:
// 5 1 2 3 4 0 6 7
for(label octanti=0; octanti<8; octanti++)
{
label octant;
if (octanti == 0)
{
// Use sampleOctant first
octant = sampleOctant;
}
else if (octanti == sampleOctant)
{
octant = 0;
}
else
{
octant = octanti;
}
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node
const treeNode<Type>* subNodePtr = getNodePtr(octant);
if (subNodePtr->bb().overlaps(tightest))
{
// there might be a better fit inside this subNode
changed |=
subNodePtr->findNearest
(
shapes,
ln,
tightest,
tightesti,
linePoint,
shapePoint
);
}
}
else
{
// Leaf: let leaf::find handle this
const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
if (subLeafPtr->bb().overlaps(tightest))
{
// there might be a better fit inside this subNode
changed |=
subLeafPtr->findNearest
(
shapes,
ln,
tightest,
tightesti,
linePoint,
shapePoint
);
}
}
}
}
return changed;
}
template <class Type>
bool treeNode<Type>::findBox
(
const Type& shapes,
const boundBox& box,
labelHashSet& elements
) const
{
bool changed = false;
bool onEdge = false;
// Estimate for where best to start searching
point boxMid(0.5*(box.min() + box.max()));
label sampleOctant = this->bb().subOctant(mid(), boxMid, onEdge);
// Go into all suboctants (one containing sample first) and update tightest.
// Order of visiting is if e.g. sampleOctant = 5:
// 5 1 2 3 4 0 6 7
for(label octanti=0; octanti<8; octanti++)
{
label octant;
if (octanti == 0)
{
// Use sampleOctant first
octant = sampleOctant;
}
else if (octanti == sampleOctant)
{
octant = 0;
}
else
{
octant = octanti;
}
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node
const treeNode<Type>* subNodePtr = getNodePtr(octant);
if (subNodePtr->bb().overlaps(box))
{
// Visit sub node.
changed |= subNodePtr->findBox(shapes, box, elements);
}
}
else
{
// Leaf: let leaf::find handle this
const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
if (subLeafPtr->bb().overlaps(box))
{
// Visit sub leaf.
changed |= subLeafPtr->findBox(shapes, box, elements);
}
}
}
}
return changed;
}
// look from <start> in current cube (given by this->bb()).
template <class Type>
const treeLeaf<Type>* treeNode<Type>::findLeafLine
(
const int level,
const Type& shapes,
point& start,
const point& end
) const
{
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLine : bb:" << this->bb() << " mid:" << mid()
<< " start:" << start << endl;
}
scalar typDim = this->bb().avgDim();
const vector direction = end - start;
// Loop on current level until start has been updated to be outside
// of this->bb(). Note that max only four subcubes can be crossed so this is
// check on whether there are any truncation error problems.
label iter = 0;
while(true)
{
if (!this->bb().contains(direction, start))
{
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLine : Start not inside bb " << this->bb()
<< ". Returning with start:" << start << " subLeaf:"
<< 0 << endl;
}
return NULL;
}
// Check if start and <end> equal
if ((mag(start - end)/typDim) < SMALL)
{
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLine : start equals end"
<< ". Returning with start:" << start << " subLeaf:"
<< 0 << endl;
}
return NULL;
}
if (iter >= 4)
{
// Too many iterations. Is hanging. Handle outside of loop.
break;
}
bool onEdge = false;
label octant = this->bb().subOctant(mid(), direction, start, onEdge);
// Try finding non-empty treeleaf in octant
const treeLeaf<Type>* leafPtr =
findLeafLineOctant
(
level,
shapes,
octant,
direction,
start,
end
);
if (leafPtr)
{
// Found treeLeaf -> return
if (debug & 2)
{
space(Pout, 2*level);
Pout<< "findLeafLine : Found treeLeaf"
<< ". Returning with start:" << start << " subLeaf:"
<< long(leafPtr) << endl;
}
return leafPtr;
}
iter++;
}
// Check if is hanging. Max 4 octants can be crossed by a straight line
FatalErrorIn
(
"treeNode<Type>::findLeafLine"
"(const label, octree<Type>&, point&,"
" const point&)"
) << "Did not leave bb " << this->bb()
<< " after " << iter
<< " iterations of updating starting point."
<< "start:" << start << " end:" << end
<< abort(FatalError);
return NULL;
}
template <class Type>
void treeNode<Type>::findLeaves
(
List<treeLeaf<Type>*>& leafArray,
label& leafIndex
) const
{
// Go into all sub boxes
for(label octant=0; octant<8; octant++)
{
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node: recurse into subnodes
const treeNode<Type>* subNodePtr = getNodePtr(octant);
subNodePtr->findLeaves(leafArray, leafIndex);
}
else
{
// Leaf: store
treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
leafArray[leafIndex++] = subLeafPtr;
}
}
}
}
template <class Type>
void treeNode<Type>::findLeaves
(
List<const treeLeaf<Type>*>& leafArray,
label& leafIndex
) const
{
// Go into all sub boxes
for(label octant=0; octant<8; octant++)
{
if (subNodes()[octant])
{
if (isNode(octant))
{
// Node: recurse into subnodes
const treeNode<Type>* subNodePtr = getNodePtr(octant);
subNodePtr->findLeaves(leafArray, leafIndex);
}
else
{
// Leaf: store
treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
leafArray[leafIndex++] = subLeafPtr;
}
}
}
}
template <class Type>
void treeNode<Type>::printNode
(
Ostream& os,
const label level
) const
{
space(os, 2*level);
os << "node:" << this->bb() << endl;
for(label octant=0; octant<8; octant++)
{
label type = getVolType(octant);
string typeString = octree<Type>::volType(type);
if (!subNodes_[octant])
{
space(os, level);
os << octant << ":" << typeString << " : null" << endl;
}
else if (isNode(octant))
{
space(os, level);
os << octant << ":" << typeString << " : node" << endl;
getNodePtr(octant)->printNode(os, level+1);
}
else
{
space(os, level);
os << octant << ":" << typeString << " : leaf" << endl;
treeLeaf<Type>* leafPtr = getLeafPtr(octant);
leafPtr->printLeaf(os, level+1);
}
}
}
template <class Type>
void treeNode<Type>::writeOBJ
(
Ostream& os,
const label level,
label& vertNo
) const
{
point midPoint(this->bb().mid());
label midVertNo = vertNo;
os << "v " << midPoint.x() << " " << midPoint.y() << " "
<< midPoint.z() << endl;
vertNo++;
for(label octant=0; octant<8; octant++)
{
if (subNodes_[octant])
{
if (isNode(octant))
{
treeNode<Type>* nodePtr = getNodePtr(octant);
point subMidPoint(nodePtr->bb().mid());
os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
<< subMidPoint.z() << endl;
os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
vertNo++;
nodePtr->writeOBJ(os, level+1, vertNo);
}
else
{
treeLeaf<Type>* leafPtr = getLeafPtr(octant);
point subMidPoint(leafPtr->bb().mid());
os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
<< subMidPoint.z() << endl;
os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
vertNo++;
//leafPtr->writeOBJ(os, level+1, vertNo);
}
}
}
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
template <class Type>
Istream& operator>>(Istream& is, treeNode<Type>& oc)
{
for(label octant = 0; octant < 8; octant++)
{
oc.subNodes_[octant] = NULL;
}
is >> oc.bb();
label nPtrs;
// Read number of entries folllowing
is >> nPtrs;
is.readBegin("treeNode");
for (label octant = 0; octant < nPtrs; octant++)
{
label index;
is >> index;
if (index >= treeNode<Type>::leafOffset)
{
// Leaf recognized by out of range index
treeLeaf<Type>* leafPtr = new treeLeaf<Type>(is);
oc.setLeafPtr(index - treeNode<Type>::leafOffset, leafPtr);
}
else
{
oc.setNodePtr(index, new treeNode<Type>(is));
}
}
// Read end of treeNode list
is.readEnd("treeNode");
// Check state of Istream
is.check("Istream& operator>>(Istream&, treeNode&)");
return is;
}
template <class Type>
Ostream& operator<<(Ostream& os, const treeNode<Type>& tn)
{
// Count valid subnodes:
// - treeNode
// - treeLeafs with non-zero cell list.
label nPtrs = 0;
for (label octant = 0; octant < 8; octant++)
{
if (tn.subNodes_[octant])
{
if
(
tn.isNode(octant)
|| (tn.getLeafPtr(octant)->indices().size() != 0)
)
{
nPtrs++;
}
}
}
// output subnodes as list of length nPtrs
os << token::SPACE << tn.bb() << token::SPACE << nPtrs
<< token::SPACE << token::BEGIN_LIST;
for (label octant = 0; octant < 8; octant++)
{
if (tn.subNodes_[octant])
{
if (tn.isNode(octant))
{
const treeNode<Type>* subNodePtr = tn.getNodePtr(octant);
// Node: output index, value
os << token::SPACE << octant << token::SPACE << *subNodePtr
<< token::NL;
}
else if (tn.getLeafPtr(octant)->indices().size() != 0)
{
// treeLeaf: mark by putting index invalid
const treeLeaf<Type>* subLeafPtr = tn.getLeafPtr(octant);
os << token::SPACE << octant + treeNode<Type>::leafOffset
<< token::SPACE << *subLeafPtr
<< token::NL;
}
}
}
os << token::SPACE << token::END_LIST;
return os;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //