Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.scijava.java3d.BHTree Maven / Gradle / Ivy
/*
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package org.scijava.java3d;
import java.util.ArrayList;
import java.util.Vector;
import org.scijava.vecmath.Point4d;
class BHTree {
Locale locale;
private BHNode root;
private BHInsertStructure insertStructure = null;
// Temporary point, so we dont generate garbage
Point4d tPoint4d = new Point4d();
// A flag to signal that number of renderAtoms sent to RenderBin is stable.
private boolean stable = false;
// An estimate of the maxmium depth of this tree (upper bound).
int estMaxDepth;
static final double LOG_OF_2 = Math.log(2);
// Assume that the size avg. leaf node is 256 bytes. For a 64bit system, we'll
// down with max depth of 56 for an ideal balance tree.
static final int DEPTH_UPPER_BOUND = 56;
static final int INCR_DEPTH_BOUND = 5;
int depthUpperBound = DEPTH_UPPER_BOUND;
BHTree() {
locale = null;
root = null;
}
BHTree(Locale loc) {
locale = loc;
root = null;
}
BHTree(BHNode bhArr[]) {
locale = null;
root = null;
create(bhArr);
}
void setLocale(Locale loc) {
locale = loc;
}
Locale getLocale() {
return locale;
}
void cluster(BHInternalNode root, BHNode[] bhArr) {
if(J3dDebug.devPhase) {
if(J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4,
"BHTree.java :In cluster length is " + bhArr.length
+ "\n")) {
for(int i=0; i= bBox.upper.x) &&
(aBox.upper.y >= bBox.upper.y) &&
(aBox.upper.z >= bBox.upper.z) &&
(aBox.lower.x <= bBox.lower.x) &&
(aBox.lower.y <= bBox.lower.y) &&
(aBox.lower.z <= bBox.lower.z));
}
BHLeafInterface selectAny(GeometryAtom atom, int accurancyMode) {
if (atom.source.geometryList == null)
return null;
BHNode bhNode = doSelectAny(atom, root, accurancyMode);
if (bhNode == null) {
return null;
}
return ((BHLeafNode) bhNode).leafIF;
}
BHLeafInterface selectAny(GeometryAtom atoms[], int size, int accurancyMode) {
BHNode bhNode = doSelectAny(atoms, size, root, accurancyMode);
if (bhNode == null) {
return null;
}
return ((BHLeafNode) bhNode).leafIF;
}
private BHNode doSelectAny(GeometryAtom atoms[],int atomSize,
BHNode bh, int accurancyMode) {
if ((bh == null) || (bh.bHull.isEmpty())) {
return null;
}
switch (bh.nodeType) {
case BHNode.BH_TYPE_LEAF:
BHLeafInterface leaf = ((BHLeafNode) bh).leafIF;
GeometryAtom atom;
int i;
if (leaf instanceof GeometryAtom) {
GeometryAtom leafAtom = (GeometryAtom) leaf;
if (((BHLeafNode) bh).isEnable() &&
leafAtom.source.isCollidable) {
// atom self intersection between atoms[]
for (i=atomSize-1; i >=0; i--) {
if (atoms[i] == leafAtom) {
return null;
}
}
for (i=atomSize-1; i >=0; i--) {
atom = atoms[i];
if ((atom.source.sourceNode != leafAtom.source.sourceNode) &&
(atom.source.collisionVwcBound.intersect(leafAtom.source.collisionVwcBound)) &&
((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) ||
((leafAtom.source.geometryList != null) &&
(atom.source.intersectGeometryList(leafAtom.source))))) {
return bh;
}
}
}
} else if (leaf instanceof GroupRetained) {
if (((BHLeafNode) bh).isEnable() &&
((GroupRetained) leaf).sourceNode.collidable) {
for (i=atomSize-1; i >=0; i--) {
atom = atoms[i];
if (atom.source.collisionVwcBound.intersect(bh.bHull) &&
((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) ||
(atom.source.intersectGeometryList(
atom.source.getCurrentLocalToVworld(0), bh.bHull)))) {
return bh;
}
}
}
}
return null;
case BHNode.BH_TYPE_INTERNAL:
for (i=atomSize-1; i >=0; i--) {
atom = atoms[i];
if (atom.source.collisionVwcBound.intersect(bh.bHull))
{
BHNode hitNode = doSelectAny(atoms,
atomSize,
((BHInternalNode) bh).getRightChild(),
accurancyMode);
if (hitNode != null)
return hitNode;
return doSelectAny(atoms, atomSize,
((BHInternalNode) bh).getLeftChild(),
accurancyMode);
}
}
return null;
}
return null;
}
private BHNode doSelectAny(GeometryAtom atom, BHNode bh, int accurancyMode) {
if ((bh == null) || (bh.bHull.isEmpty())) {
return null;
}
switch (bh.nodeType) {
case BHNode.BH_TYPE_LEAF:
BHLeafInterface leaf = ((BHLeafNode) bh).leafIF;
if (leaf instanceof GeometryAtom) {
GeometryAtom leafAtom = (GeometryAtom) leaf;
if ((atom.source.sourceNode != leafAtom.source.sourceNode) &&
(((BHLeafNode) bh).isEnable()) &&
(leafAtom.source.isCollidable) &&
(atom.source.collisionVwcBound.intersect(leafAtom.source.collisionVwcBound)) &&
((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) ||
((leafAtom.source.geometryList != null) &&
(atom.source.intersectGeometryList(leafAtom.source))))) {
return bh;
}
} else if (leaf instanceof GroupRetained) {
if (((BHLeafNode) bh).isEnable() &&
((GroupRetained) leaf).sourceNode.collidable &&
atom.source.collisionVwcBound.intersect(bh.bHull) &&
((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) ||
(atom.source.intersectGeometryList(
atom.source.getCurrentLocalToVworld(0), bh.bHull)))) {
return bh;
}
}
return null;
case BHNode.BH_TYPE_INTERNAL:
if (atom.source.collisionVwcBound.intersect(bh.bHull)) {
BHNode hitNode = doSelectAny(atom,
((BHInternalNode) bh).getRightChild(),
accurancyMode);
if (hitNode != null)
return hitNode;
return doSelectAny(atom,
((BHInternalNode) bh).getLeftChild(),
accurancyMode);
}
return null;
}
return null;
}
BHLeafInterface selectAny(Bounds bound, int accurancyMode,
NodeRetained armingNode) {
if (bound == null) {
return null;
}
BHNode bhNode = doSelectAny(bound, root, accurancyMode, armingNode);
if (bhNode == null) {
return null;
}
return ((BHLeafNode) bhNode).leafIF;
}
private BHNode doSelectAny(Bounds bound, BHNode bh, int accurancyMode,
NodeRetained armingNode) {
if ((bh == null) || (bh.bHull.isEmpty())) {
return null;
}
switch (bh.nodeType) {
case BHNode.BH_TYPE_LEAF:
BHLeafInterface leaf = ((BHLeafNode) bh).leafIF;
if (leaf instanceof GeometryAtom) {
GeometryAtom leafAtom = (GeometryAtom) leaf;
if ((((BHLeafNode) bh).isEnable()) &&
(leafAtom.source.isCollidable) &&
(bound.intersect(leafAtom.source.collisionVwcBound)) &&
((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) ||
((leafAtom.source.geometryList != null) &&
(leafAtom.source.intersectGeometryList(
leafAtom.source.getCurrentLocalToVworld(0), bound))))) {
return bh;
}
} else if (leaf instanceof GroupRetained) {
if ((leaf != armingNode) &&
((BHLeafNode) bh).isEnable() &&
((GroupRetained) leaf).sourceNode.collidable &&
bound.intersect(bh.bHull)) {
return bh;
}
}
return null;
case BHNode.BH_TYPE_INTERNAL:
if (bound.intersect(bh.bHull)) {
BHNode hitNode = doSelectAny(bound,
((BHInternalNode) bh).getRightChild(),
accurancyMode,
armingNode);
if (hitNode != null)
return hitNode;
return doSelectAny(bound,
((BHInternalNode) bh).getLeftChild(),
accurancyMode,
armingNode);
}
return null;
}
return null;
}
BHLeafInterface selectAny(Bounds bound, int accurancyMode,
GroupRetained armingGroup) {
if (bound == null) {
return null;
}
BHNode bhNode = doSelectAny(bound, root, accurancyMode, armingGroup);
if (bhNode == null) {
return null;
}
return ((BHLeafNode) bhNode).leafIF;
}
private BHNode doSelectAny(Bounds bound, BHNode bh, int accurancyMode,
GroupRetained armingGroup) {
if ((bh == null) || (bh.bHull.isEmpty())) {
return null;
}
switch (bh.nodeType) {
case BHNode.BH_TYPE_LEAF:
BHLeafInterface leaf = ((BHLeafNode) bh).leafIF;
if (leaf instanceof GeometryAtom) {
GeometryAtom leafAtom = (GeometryAtom) leaf;
if ((((BHLeafNode) bh).isEnable()) &&
(leafAtom.source.isCollidable) &&
(bound.intersect(leafAtom.source.collisionVwcBound)) &&
(!isDescendent(leafAtom.source.sourceNode,
armingGroup, leafAtom.source.key)) &&
((accurancyMode == WakeupOnCollisionEntry.USE_BOUNDS) ||
((leafAtom.source.geometryList != null) &&
(leafAtom.source.intersectGeometryList(
leafAtom.source.getCurrentLocalToVworld(0), bound))))) {
return bh;
}
} else if (leaf instanceof GroupRetained) {
GroupRetained group = (GroupRetained) leaf;
if (((BHLeafNode) bh).isEnable() &&
group.sourceNode.collidable &&
bound.intersect(bh.bHull) &&
!isDescendent(group.sourceNode, armingGroup, group.key)) {
return bh;
}
}
return null;
case BHNode.BH_TYPE_INTERNAL:
if (bound.intersect(bh.bHull)) {
BHNode hitNode = doSelectAny(bound,
((BHInternalNode) bh).getRightChild(),
accurancyMode,
armingGroup);
if (hitNode != null)
return hitNode;
return doSelectAny(bound,
((BHInternalNode) bh).getLeftChild(),
accurancyMode,
armingGroup);
}
return null;
}
return null;
}
// Return true if node is a descendent of group
private boolean isDescendent(NodeRetained node,
GroupRetained group,
HashKey key) {
synchronized (group.universe.sceneGraphLock) {
if (node.inSharedGroup) {
// getlastNodeId() will destroy this key
if (key != null) {
key = new HashKey(key);
}
}
do {
if (node == group) {
return true;
}
if (node instanceof SharedGroupRetained) {
// retrieve the last node ID
String nodeId = key.getLastNodeId();
NodeRetained prevNode = node;
Vector parents = ((SharedGroupRetained)node).parents;
for(int i=parents.size()-1; i >=0; i--) {
NodeRetained link = parents.get(i);
if (link.nodeId.equals(nodeId)) {
node = link;
break;
}
}
if (prevNode == node) {
// branch is already detach
return true;
}
}
node = node.parent;
} while (node != null); // reach Locale
}
return false;
}
void select(PickShape pickShape, UnorderList hitArrList) {
if((pickShape == null)||(root == null))
return;
doSelect(pickShape, hitArrList, root, tPoint4d);
}
private void doSelect(PickShape pickShape, UnorderList hitArrList,
BHNode bh, Point4d pickPos) {
if ((bh == null) || (bh.bHull.isEmpty())) {
return;
}
switch(bh.nodeType) {
case BHNode.BH_TYPE_LEAF:
if (((BHLeafNode)(bh)).isEnable() &&
(((BHLeafNode) bh).leafIF instanceof GeometryAtom) &&
((GeometryAtom) (((BHLeafNode)
bh).leafIF)).source.isPickable &&
pickShape.intersect(bh.bHull, pickPos)) {
hitArrList.add(bh);
}
break;
case BHNode.BH_TYPE_INTERNAL:
if (pickShape.intersect(bh.bHull, pickPos)) {
doSelect(pickShape,
hitArrList,
((BHInternalNode)bh).getRightChild(),
pickPos);
doSelect(pickShape,
hitArrList,
((BHInternalNode)bh).getLeftChild(),
pickPos);
}
break;
}
}
BHNode selectAny(PickShape pickShape) {
if((pickShape == null)||(root == null))
return null;
return doSelectAny(pickShape, root, tPoint4d);
}
private BHNode doSelectAny(PickShape pickShape, BHNode bh, Point4d pickPos) {
BHNode hitNode = null;
if((bh == null) || (bh.bHull.isEmpty()))
return null;
switch(bh.nodeType) {
case BHNode.BH_TYPE_LEAF:
if (((BHLeafNode)(bh)).isEnable() &&
(((BHLeafNode) bh).leafIF instanceof GeometryAtom) &&
((GeometryAtom) (((BHLeafNode)
bh).leafIF)).source.isPickable &&
pickShape.intersect(bh.bHull, pickPos)) {
return bh;
}
break;
case BHNode.BH_TYPE_INTERNAL:
if (pickShape.intersect(bh.bHull, pickPos)) {
hitNode = doSelectAny(pickShape,
((BHInternalNode)bh).getRightChild(),
pickPos);
if (hitNode != null) {
return hitNode;
}
return doSelectAny(pickShape,
((BHInternalNode)bh).getLeftChild(),
pickPos);
}
break;
}
return null;
}
private void create(BHNode bhArr[]) {
int i;
if(bhArr == null) {
root = null;
return;
}
if(bhArr.length == 1) {
bhArr[0].computeBoundingHull();
root = (BHNode)bhArr[0];
return;
}
int centerValuesIndex[] = new int[bhArr.length];
float centerValues[][] = computeCenterValues(bhArr, centerValuesIndex);
/*
System.err.println("Length of array is " + bhArr.length);
for(int kk=0; kk depthUpperBound) {
int maxDepth = root.computeMaxDepth(0);
int leafCount = root.countNumberOfLeaves();
double compDepth = Math.log(leafCount)/LOG_OF_2;
/*
System.err.println("BHTree - evaluate for reConstructTree ...");
System.err.println("compDepth " + compDepth);
System.err.println("maxDepth " + maxDepth);
System.err.println("leafCount " + leafCount);
*/
// Upper bound guard.
if(maxDepth > depthUpperBound) {
reConstructTree(leafCount);
maxDepth = root.computeMaxDepth(0);
/*
System.err.println("BHTree - Did reConstructTree ...");
System.err.println("compDepth " + compDepth);
System.err.println("maxDepth " + maxDepth);
*/
}
// Adjust depthUpperBound according to app. need.
// If we encounter lots of overlapping bounds, the re-balanced
// tree may not be an ideal balance tree. So there might be a
// likehood of maxDepth exceeding the preset depthUpperBound.
if(maxDepth > depthUpperBound) {
depthUpperBound = depthUpperBound + INCR_DEPTH_BOUND;
}else if((depthUpperBound != DEPTH_UPPER_BOUND) &&
(maxDepth * 1.5 < depthUpperBound)) {
depthUpperBound = depthUpperBound - INCR_DEPTH_BOUND;
if(depthUpperBound < DEPTH_UPPER_BOUND) {
// Be sure that DEPTH_UPPER_BOUND is the min.
depthUpperBound = DEPTH_UPPER_BOUND;
}
}
// This is the only place for resetting estMaxDepth to the tree real
// maxDepth. Hence in cases where tree may get deteriorate fast, such
// as multiple inserts and deletes frequently. estMaxDepth is accuminated,
// and will lead to tree re-evaluation and possibly re-balancing.
estMaxDepth = maxDepth;
}
}
// mark all elements of the node and its parent as needing updating
private void markParentChain(BHNode[] nArr, int size) {
BHNode node;
for(int i=0; i=0; i--) {
sumCenters[i] = 0.0f;
ss[i] = 0.0f;
}
for(i=arrLen-1; i>=0 ; i--) {
sumCenters[0] += centerValues[centerValuesIndex[i]][0];
sumCenters[1] += centerValues[centerValuesIndex[i]][1];
sumCenters[2] += centerValues[centerValuesIndex[i]][2];
}
means[0] = sumCenters[0]/(float)arrLen;
means[1] = sumCenters[1]/(float)arrLen;
means[2] = sumCenters[2]/(float)arrLen;
for(i=arrLen-1; i>=0 ; i--) {
temp = (centerValues[centerValuesIndex[i]][0] - means[0]);
ss[0] += (temp*temp);
temp = (centerValues[centerValuesIndex[i]][1] - means[1]);
ss[1] += (temp*temp);
temp = (centerValues[centerValuesIndex[i]][2] - means[2]);
ss[2] += (temp*temp);
}
}
// find the split axis (the highest ss and return its index) for
// a given set of ss values
int findSplitAxis ( float ss[] ) {
int splitAxis = -1;
float maxSS = 0.0f;
// the largest ss index value
for (int i=0; i < 3; i++) {
if ( ss[i] > maxSS ) {
maxSS = ss[i];
splitAxis = i;
}
}
return splitAxis;
}
// Recursive method for constructing a binary tree.
void constructTree( BHInternalNode parent, BHNode bhArr[],
float[][] centerValues,
int[] centerValuesIndex ){
int i, splitAxis;
int rightSetCount = 0;
int leftSetCount = 0;
float means[] = new float[3];
float ss[] = new float[3];
if(J3dDebug.devPhase)
if ( bhArr.length <= 1 ) {
// this is only here for debugging can be removed after testing
// to ensure that it never gets called
J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_1,
"constructTree - bhArr.length <= 1. Bad !!!\n");
}
computeMeansAndSumSquares(centerValues, centerValuesIndex, means, ss);
splitAxis = findSplitAxis(ss);
// an array of decision variables for storing the values of inside
// the right or left set for a particular element of bhArr.
// true if its in the left set, false if its in the right set
boolean leftOrRightSet[] = new boolean[bhArr.length];
if ( splitAxis == -1 ) {
// This is bad. Since we can't find a split axis, the best thing
// to do is to split the set in two sets; each with about the
// same number of elements. By doing this we can avoid constructing
// a skew tree.
// split elements into half.
for ( i=0; i < bhArr.length; i++) {
if(leftSetCount > rightSetCount) {
rightSetCount++;
leftOrRightSet[i] = false;
} else {
leftSetCount++;
leftOrRightSet[i] = true;
}
}
}
else {
for ( i=0; i < bhArr.length; i++) {
// the split criterion, special multiple equals cases added
if ( centerValues[centerValuesIndex[i]][splitAxis] <
means[splitAxis]) {
if(J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4,
"Found a left element\n");
leftSetCount++;
leftOrRightSet[i] = true;
} else if ( centerValues[centerValuesIndex[i]][splitAxis] >
means[splitAxis]) {
if(J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4,
"Found a right element\n");
rightSetCount++;
leftOrRightSet[i] = false;
} else {
if(J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4,
"Found an equal element\n");
if(leftSetCount > rightSetCount) {
rightSetCount++;
leftOrRightSet[i] = false;
} else {
leftSetCount++;
leftOrRightSet[i] = true;
}
}
}
}
if(J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_2,
"LeftSetCount " + leftSetCount + " RightSetCount "+
rightSetCount + "\n");
// Don't think that this guard is needed, but still like to have it.
// Just in case, bad means and the sum of squares might lead us into the guard.
if (leftSetCount == bhArr.length) {
if(J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_1,
"Split Axis of = " + splitAxis + " didn't yield "+
"any split among the objects ?\n");
// split elements into half
rightSetCount = 0;
leftSetCount = 0;
for ( i=0; i < bhArr.length; i++) {
if(leftSetCount > rightSetCount) {
rightSetCount++;
leftOrRightSet[i] = false;
} else {
leftSetCount++;
leftOrRightSet[i] = true;
}
}
} else if (rightSetCount == bhArr.length) {
if(J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_1,
"Split Axis of = " + splitAxis + " didn't yield "+
"any split among the objects ?\n");
// split elements into half
rightSetCount = 0;
leftSetCount = 0;
for ( i=0; i < bhArr.length; i++) {
if(leftSetCount > rightSetCount) {
rightSetCount++;
leftOrRightSet[i] = false;
} else {
leftSetCount++;
leftOrRightSet[i] = true;
}
}
}
if(J3dDebug.devPhase)
if(J3dDebug.doDebug(J3dDebug.bHTree, J3dDebug.LEVEL_4))
// check to make sure that rightSet and leftSet sum to the
// number of elements in the original array.
if ( bhArr.length != (rightSetCount + leftSetCount) ) {
System.err.println("An error has occurred in spliting");
}
BHNode rightSet[] = new BHNode[rightSetCount];
BHNode leftSet[] = new BHNode[leftSetCount];
int centerValuesIndexR[] = new int[rightSetCount];
int centerValuesIndexL[] = new int[leftSetCount];
rightSetCount = 0;
leftSetCount = 0;
for (i=0; i < bhArr.length; i++) {
if ( leftOrRightSet[i] ) { // element in left set
leftSet[leftSetCount] = bhArr[i];
centerValuesIndexL[leftSetCount] = centerValuesIndex[i];
leftSetCount++;
} else {
rightSet[rightSetCount] = bhArr[i];
centerValuesIndexR[rightSetCount] = centerValuesIndex[i];
rightSetCount++;
}
}
if (rightSet.length != 1) {
parent.rChild = new BHInternalNode();
parent.rChild.setParent(parent);
constructTree((BHInternalNode)(parent.rChild), rightSet, centerValues,
centerValuesIndexR);
} else {
parent.rChild = rightSet[0];
parent.rChild.setParent(parent);
}
if (leftSet.length != 1) {
parent.lChild = new BHInternalNode();
parent.lChild.setParent(parent);
constructTree((BHInternalNode)(parent.lChild), leftSet, centerValues,
centerValuesIndexL);
} else {
parent.lChild = leftSet[0];
parent.lChild.setParent(parent);
}
parent.combineBHull(parent.rChild, parent.lChild);
}
void reConstructTree(int numOfLeaf) {
if(root == null)
return;
BHNode bhArr[] = new BHNode[numOfLeaf];
int index[] = new int[1];
index[0] = 0;
root.destroyTree(bhArr, index);
/*
if(bhArr.length != index[0])
System.err.println("BHTree - This isn't right!!! - bhArr.length " +
bhArr.length + " index " + index[0]);
*/
create(bhArr);
}
void gatherTreeStatistics() {
int leafCount = root.countNumberOfLeaves();
int internalCount = root.countNumberOfInternals();
int maxDepth = root.computeMaxDepth(0);
float averageDepth = root.computeAverageLeafDepth ( leafCount, 0);
System.err.println("Statistics for tree = " + this);
System.err.println("Total Number of nodes in tree = " +
(leafCount + internalCount) );
System.err.println("Number of Leaf Nodes = " + leafCount );
System.err.println("Number of Internal Nodes = " + internalCount );
System.err.println("Maximum Leaf depth = " + maxDepth );
System.err.println("Average Leaf depth = " + averageDepth );
System.err.println("root.bHull = " + root.bHull);
// printTree(root);
}
void printTree(BHNode bh) {
if(bh!= null) {
if(bh.nodeType == BHNode.BH_TYPE_INTERNAL) {
System.err.println("BH_TYPE_INTERNAL - bHull : " + bh);
System.err.println(bh.bHull);
System.err.println("rChild : " + ((BHInternalNode)bh).rChild +
" lChild : " + ((BHInternalNode)bh).lChild);
printTree(((BHInternalNode)bh).rChild);
printTree(((BHInternalNode)bh).lChild);
}
else if(bh.nodeType == BHNode.BH_TYPE_LEAF) {
System.err.println("BH_TYPE_LEAF - bHull : " + bh);
System.err.println(bh.bHull);
}
}
}
}