///*
// * __ .__ .__ ._____.
// * _/ |_ _______ __|__| ____ | | |__\_ |__ ______
// * \ __\/ _ \ \/ / |/ ___\| | | || __ \ / ___/
// * | | ( <_> > <| \ \___| |_| || \_\ \\___ \
// * |__| \____/__/\_ \__|\___ >____/__||___ /____ >
// * \/ \/ \/ \/
// *
// * Copyright (c) 2006-2011 Karsten Schmidt
// *
// * This library is free software; you can redistribute it and/or
// * modify it under the terms of the GNU Lesser General Public
// * License as published by the Free Software Foundation; either
// * version 2.1 of the License, or (at your option) any later version.
// *
// * http://creativecommons.org/licenses/LGPL/2.1/
// *
// * This library 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
// * Lesser General Public License for more details.
// *
// * You should have received a copy of the GNU Lesser General Public
// * License along with this library; if not, write to the Free Software
// * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
// */
//
//package toxi.geom;
//
//import java.util.ArrayList;
//import java.util.Collection;
//import java.util.List;
//
///**
// * Implements a spatial subdivision tree to work efficiently with large numbers
// * of 3D particles. This octree can only be used for particle type objects and
// * does NOT support 3D mesh geometry as other forms of Octrees do.
// *
// * For further reference also see the OctreeDemo in the /examples folder.
// *
// */
//public class PointOctree extends AABB implements Shape3D {
//
// /**
// * alternative tree recursion limit, number of world units when cells are
// * not subdivided any further
// */
// public float minNodeSize = 4;
//
// /**
// *
// */
// public final PointOctree parent;
//
// public PointOctree[] children;
//
// protected byte numChildren;
//
// protected ArrayList<XYZ> points;
//
// protected float size, halfSize;
//
// protected Vec3D offset;
//
// public int depth = 0;
//
// private boolean isAutoReducing = false;
//
// /**
// * Constructs a new PointOctree node within the AABB cube volume: {o.x, o.y,
// * o.z} ... {o.x+size, o.y+size, o.z+size}
// *
// * @param p
// * parent node
// * @param o
// * tree origin
// * @param halfSize
// * half length of the tree volume along a single axis
// */
// private PointOctree(PointOctree p, Vec3D o, float halfSize) {
// super(o.plus(halfSize, halfSize, halfSize), new Vec3D(halfSize,
// halfSize, halfSize));
//
// this.parent = p;
// this.halfSize = halfSize;
// this.size = halfSize * 2;
// this.offset = o;
// this.numChildren = 0;
// if (parent != null) {
// depth = parent.depth + 1;
// minNodeSize = parent.minNodeSize;
// }
// }
//
// /**
// * Constructs a new PointOctree node within the AABB cube volume: {o.x, o.y,
// * o.z} ... {o.x+size, o.y+size, o.z+size}
// *
// * @param o
// * tree origin
// * @param size
// * size of the tree volume along a single axis
// */
// public PointOctree(Vec3D o, float size) {
// this(null, o, size / 2);
// }
//
// /**
// * Adds all points of the collection to the octree. IMPORTANT: Points need
// * be of type Vec3D or have subclassed it.
// *
// * @param points
// * point collection
// * @return true, if all points have been added successfully.
// */
// public boolean addAll(Collection<XYZ> points) {
// boolean addedAll = true;
// for (XYZ p : points) {
// addedAll &= addPoint(p);
// }
// return addedAll;
// }
//
// /**
// * Adds a new point/particle to the tree structure. All points are stored
// * within leaf nodes only. The tree implementation is using lazy
// * instantiation for all intermediate tree levels.
// *
// * @param p
// * @return true, if point has been added successfully
// */
// public boolean addPoint(XYZ p) {
// // check if point is inside cube
// if (containsPoint(p)) {
// // only add points to leaves for now
// if (halfSize <= minNodeSize) {
// if (points == null) {
// points = new ArrayList();
// }
// points.add(p);
// return true;
// } else {
// Vec3D plocal = p.sub(offset);
// if (children == null) {
// children = new PointOctree[8];
// }
// int octant = getOctantID(plocal);
// if (children[octant] == null) {
// Vec3D off = offset.plus(new Vec3D(
// (octant & 1) != 0 ? halfSize : 0,
// (octant & 2) != 0 ? halfSize : 0,
// (octant & 4) != 0 ? halfSize : 0));
// children[octant] = new PointOctree(this, off,
// halfSize * 0.5f);
// numChildren++;
// }
// return children[octant].addPoint(p);
// }
// }
// return false;
// }
//
// /**
// * Applies the given {@link OctreeVisitor} implementation to this node and
// * all of its children.
// */
// public void applyVisitor(OctreeVisitor visitor) {
// visitor.visitNode(this);
// if (numChildren > 0) {
// for (PointOctree c : children) {
// if (c != null) {
// c.applyVisitor(visitor);
// }
// }
// }
// }
//
// public boolean containsPoint(roVec3D p) {
// return p.isInAABB(this);
// }
//
// public void empty() {
// numChildren = 0;
// children = null;
// points = null;
// }
//
// /**
// * @return a copy of the child nodes array
// */
// public PointOctree[] getChildren() {
// if (children != null) {
// PointOctree[] clones = new PointOctree[8];
// System.arraycopy(children, 0, clones, 0, 8);
// return clones;
// }
// return null;
// }
//
// /**
// * @return the depth
// */
// public int getDepth() {
// return depth;
// }
//
// /**
// * Finds the leaf node which spatially relates to the given point
// *
// * @param p
// * point to check
// * @return leaf node or null if point is outside the tree dimensions
// */
// public PointOctree getLeafForPoint(XYZ p) {
// // if not a leaf node...
// if (p.isInAABB(this)) {
// if (numChildren > 0) {
// int octant = getOctantID(p.sub(offset));
// if (children[octant] != null) {
// return children[octant].getLeafForPoint(p);
// }
// } else if (points != null) {
// return this;
// }
// }
// return null;
// }
//
// /**
// * Returns the minimum size of nodes (in world units). This value acts as
// * tree recursion limit since nodes smaller than this size are not
// * subdivided further. Leaf node are always smaller or equal to this size.
// *
// * @return the minimum size of tree nodes
// */
// public float getMinNodeSize() {
// return minNodeSize;
// }
//
// public float getNodeSize() {
// return size;
// }
//
// /**
// * @return the number of child nodes (max. 8)
// */
// public int getNumChildren() {
// return numChildren;
// }
//
// /**
// * Computes the local child octant/cube index for the given point
// *
// * @param plocal
// * point in the node-local coordinate system
// * @return octant index
// */
// protected final int getOctantID(Vec3D plocal) {
// return (plocal.x >= halfSize ? 1 : 0) + (plocal.y >= halfSize ? 2 : 0)
// + (plocal.z >= halfSize ? 4 : 0);
// }
//
// /**
// * @return the offset
// */
// public roVec3D getOffset() {
// return offset;
// }
//
// /**
// * @return the parent
// */
// public PointOctree getParent() {
// return parent;
// }
//
// /**
// * @return the points
// */
// public List<XYZ> getPoints() {
// List<XYZ> results = null;
// if (points != null) {
// results = new ArrayList(points);
// } else if (numChildren > 0) {
// for (int i = 0; i < 8; i++) {
// if (children[i] != null) {
// List<XYZ> childPoints = children[i].getPoints();
// if (childPoints != null) {
// if (results == null) {
// results = new ArrayList();
// }
// results.addAll(childPoints);
// }
// }
// }
// }
// return results;
// }
//
// /**
// * Selects all stored points within the given axis-aligned bounding box.
// *
// * @param b
// * AABB
// * @return all points with the box volume
// */
// public List<XYZ> getPointsWithinBox(BB b) {
// ArrayList<XYZ> results = null;
// if (this.intersectsBox(b)) {
// if (points != null) {
// for (XYZ q : points) {
// if (q.isInAABB(b)) {
// if (results == null) {
// results = new ArrayList();
// }
// results.add(q);
// }
// }
// } else if (numChildren > 0) {
// for (int i = 0; i < 8; i++) {
// if (children[i] != null) {
// List<XYZ> points = children[i].getPointsWithinBox(b);
// if (points != null) {
// if (results == null) {
// results = new ArrayList();
// }
// results.addAll(points);
// }
// }
// }
// }
// }
// return results;
// }
//
// /**
// * Selects all stored points within the given sphere volume
// *
// * @param s
// * sphere
// * @return selected points
// */
// public List<XYZ> getPointsWithinSphere(Sphere s) {
// ArrayList<XYZ> results = null;
// if (this.intersectsSphere(s)) {
// if (points != null) {
// for (XYZ q : points) {
// if (s.containsPoint(q)) {
// if (results == null) {
// results = new ArrayList();
// }
// results.add(q);
// }
// }
// } else if (numChildren > 0) {
// for (int i = 0; i < 8; i++) {
// if (children[i] != null) {
// List<XYZ> points = children[i]
// .getPointsWithinSphere(s);
// if (points != null) {
// if (results == null) {
// results = new ArrayList();
// }
// results.addAll(points);
// }
// }
// }
// }
// }
// return results;
// }
//
// /**
// * Selects all stored points within the given sphere volume
// *
// * @param sphereOrigin
// * @param clipRadius
// * @return selected points
// */
// public List<XYZ> getPointsWithinSphere(Vec3D sphereOrigin,
// float clipRadius) {
// return getPointsWithinSphere(new Sphere(sphereOrigin, clipRadius));
// }
//
// /**
// * @return the size
// */
// public float getSize() {
// return size;
// }
//
// private void reduceBranch() {
// if (points != null && points.size() == 0) {
// points = null;
// }
// if (numChildren > 0) {
// for (int i = 0; i < 8; i++) {
// if (children[i] != null && children[i].points == null) {
// children[i] = null;
// }
// }
// }
// if (parent != null) {
// parent.reduceBranch();
// }
// }
//
// /**
// * Removes a point from the tree and (optionally) tries to release memory by
// * reducing now empty sub-branches.
// *
// * @param p
// * point to delete
// * @return true, if the point was found & removed
// */
// public boolean remove(XYZ p) {
// boolean found = false;
// PointOctree leaf = getLeafForPoint(p);
// if (leaf != null) {
// if (leaf.points.remove(p)) {
// found = true;
// if (isAutoReducing && leaf.points.size() == 0) {
// leaf.reduceBranch();
// }
// }
// }
// return found;
// }
//
// public void removeAll(Collection<XYZ> points) {
// for (XYZ p : points) {
// remove(p);
// }
// }
//
// /**
// * @param minNodeSize
// */
// public void setMinNodeSize(float minNodeSize) {
// this.minNodeSize = minNodeSize * 0.5f;
// }
//
// /**
// * Enables/disables auto reduction of branches after points have been
// * deleted from the tree. Turned off by default.
// *
// * @param state
// * true, to enable feature
// */
// public void setTreeAutoReduction(boolean state) {
// isAutoReducing = state;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see toxi.geom.AABB#toString()
// */
// public String toString() {
// return "<octree> offset: " + super.toString() + " size: " + size;
// }
//}