/**
*
*/
package wblut.geom;
import wblut.hemesh.HE_Face;
import wblut.hemesh.HE_Mesh;
import wblut.hemesh.HE_Selection;
// TODO: Auto-generated Javadoc
/**
* The Class WB_AABBTree.
*
* @author Frederik Vanhoutte, W:Blut
*/
public class WB_AABBTree {
/** The root. */
private WB_AABBNode root;
/** The max level. */
private final int maxLevel;
/** The max number of faces. */
private final int maxNumberOfFaces;
/**
* Instantiates a new w b_ aabb tree.
*
* @param mesh the mesh
* @param mnof the mnof
*/
public WB_AABBTree(final HE_Mesh mesh, final int mnof) {
maxLevel = 2 * (int) Math.ceil(Math.log(mesh.numberOfFaces())
/ Math.log(3.0));
maxNumberOfFaces = Math.max(1, mnof);
buildTree(mesh);
}
/**
* Builds the tree.
*
* @param mesh the mesh
*/
private void buildTree(final HE_Mesh mesh) {
root = new WB_AABBNode();
final HE_Selection faces = new HE_Selection(mesh);
faces.addFaces(mesh.getFacesAsList());
buildNode(root, faces, mesh, 0);
}
/**
* Builds the node.
*
* @param node the node
* @param faces the faces
* @param mesh the mesh
* @param level the level
*/
private void buildNode(final WB_AABBNode node, final HE_Selection faces,
final HE_Mesh mesh, final int level) {
node.level = level;
faces.collectVertices();
node.aabb = faces.getAABB();
if ((level == maxLevel) || (faces.numberOfFaces() <= maxNumberOfFaces)) {
node.faces.addAll(faces.getFacesAsList());
node.isLeaf = true;
} else {
final HE_Selection pos = new HE_Selection(mesh);
final HE_Selection neg = new HE_Selection(mesh);
final HE_Selection mid = new HE_Selection(mesh);
final WB_Vector3d dir = new WB_Vector3d();
if (level % 3 == 0) {
dir.set(0, 0, 1);
} else if (level % 3 == 1) {
dir.set(0, 1, 0);
} else {
dir.set(1, 0, 0);
}
node.separator = new WB_Plane(node.aabb.getCenter(), dir);
for (final HE_Face face : faces.getFacesAsList()) {
final WB_ClassifyPolygonToPlane cptp = node.separator
.classifyPolygonToPlane(face.toPolygon());
if (cptp == WB_ClassifyPolygonToPlane.POLYGON_STRADDLING_PLANE) {
mid.add(face);
} else if (cptp == WB_ClassifyPolygonToPlane.POLYGON_BEHIND_PLANE) {
neg.add(face);
} else {
pos.add(face);
}
}
node.isLeaf = true;
if (mid.numberOfFaces() > 0) {
node.mid = new WB_AABBNode();
buildNode(node.mid, mid, mesh, level + 1);
node.isLeaf = false;
}
if (neg.numberOfFaces() > 0) {
node.negative = new WB_AABBNode();
buildNode(node.negative, neg, mesh, level + 1);
node.isLeaf = false;
}
if (pos.numberOfFaces() > 0) {
node.positive = new WB_AABBNode();
buildNode(node.positive, pos, mesh, level + 1);
node.isLeaf = false;
}
}
}
/**
* Gets the root.
*
* @return the root
*/
public WB_AABBNode getRoot() {
return root;
}
}