API Docs for: 0.6.1
Show:

File: src/utils/Octree.js

var AABB = require('../collision/AABB');
var Vec3 = require('../math/Vec3');
module.exports = Octree;
/**
 * @class OctreeNode
 * @param {object} [options]
 * @param {Octree} [options.root]
 * @param {AABB} [options.aabb]
 */
function OctreeNode(options){
 options = options || {};
 /**
 * The root node
 * @property {OctreeNode} root
 */
 this.root = options.root || null;
 /**
 * Boundary of this node
 * @property {AABB} aabb
 */
 this.aabb = options.aabb ? options.aabb.clone() : new AABB();
 /**
 * Contained data at the current node level.
 * @property {Array} data
 */
 this.data = [];
 /**
 * Children to this node
 * @property {Array} children
 */
 this.children = [];
}
/**
 * @class Octree
 * @param {AABB} aabb The total AABB of the tree
 * @param {object} [options]
 * @param {number} [options.maxDepth=8]
 * @extends OctreeNode
 */
function Octree(aabb, options){
 options = options || {};
 options.root = null;
 options.aabb = aabb;
 OctreeNode.call(this, options);
 /**
 * Maximum subdivision depth
 * @property {number} maxDepth
 */
 this.maxDepth = typeof(options.maxDepth) !== 'undefined' ? options.maxDepth : 8;
}
Octree.prototype = new OctreeNode();
OctreeNode.prototype.reset = function(aabb, options){
 this.children.length = this.data.length = 0;
};
/**
 * Insert data into this node
 * @method insert
 * @param {AABB} aabb
 * @param {object} elementData
 * @return {boolean} True if successful, otherwise false
 */
OctreeNode.prototype.insert = function(aabb, elementData, level){
 var nodeData = this.data;
 level = level || 0;
 // Ignore objects that do not belong in this node
 if (!this.aabb.contains(aabb)){
 return false; // object cannot be added
 }
 var children = this.children;
 if(level < (this.maxDepth || this.root.maxDepth)){
 // Subdivide if there are no children yet
 var subdivided = false;
 if (!children.length){
 this.subdivide();
 subdivided = true;
 }
 // add to whichever node will accept it
 for (var i = 0; i !== 8; i++) {
 if (children[i].insert(aabb, elementData, level + 1)){
 return true;
 }
 }
 if(subdivided){
 // No children accepted! Might as well just remove em since they contain none
 children.length = 0;
 }
 }
 // Too deep, or children didnt want it. add it in current node
 nodeData.push(elementData);
 return true;
};
var halfDiagonal = new Vec3();
/**
 * Create 8 equally sized children nodes and put them in the .children array.
 * @method subdivide
 */
OctreeNode.prototype.subdivide = function() {
 var aabb = this.aabb;
 var l = aabb.lowerBound;
 var u = aabb.upperBound;
 var children = this.children;
 children.push(
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,0) }) }),
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,0) }) }),
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,0) }) }),
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,1) }) }),
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,1) }) }),
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,1) }) }),
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,1) }) }),
 new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,0) }) })
 );
 u.vsub(l, halfDiagonal);
 halfDiagonal.scale(0.5, halfDiagonal);
 var root = this.root || this;
 for (var i = 0; i !== 8; i++) {
 var child = children[i];
 // Set current node as root
 child.root = root;
 // Compute bounds
 var lowerBound = child.aabb.lowerBound;
 lowerBound.x *= halfDiagonal.x;
 lowerBound.y *= halfDiagonal.y;
 lowerBound.z *= halfDiagonal.z;
 lowerBound.vadd(l, lowerBound);
 // Upper bound is always lower bound + halfDiagonal
 lowerBound.vadd(halfDiagonal, child.aabb.upperBound);
 }
};
/**
 * Get all data, potentially within an AABB
 * @method aabbQuery
 * @param {AABB} aabb
 * @param {array} result
 * @return {array} The "result" object
 */
OctreeNode.prototype.aabbQuery = function(aabb, result) {
 var nodeData = this.data;
 // abort if the range does not intersect this node
 // if (!this.aabb.overlaps(aabb)){
 // return result;
 // }
 // Add objects at this level
 // Array.prototype.push.apply(result, nodeData);
 // Add child data
 // @todo unwrap recursion into a queue / loop, that's faster in JS
 var children = this.children;
 // for (var i = 0, N = this.children.length; i !== N; i++) {
 // children[i].aabbQuery(aabb, result);
 // }
 var queue = [this];
 while (queue.length) {
 var node = queue.pop();
 if (node.aabb.overlaps(aabb)){
 Array.prototype.push.apply(result, node.data);
 }
 Array.prototype.push.apply(queue, node.children);
 }
 return result;
};
var tmpAABB = new AABB();
/**
 * Get all data, potentially intersected by a ray.
 * @method rayQuery
 * @param {Ray} ray
 * @param {Transform} treeTransform
 * @param {array} result
 * @return {array} The "result" object
 */
OctreeNode.prototype.rayQuery = function(ray, treeTransform, result) {
 // Use aabb query for now.
 // @todo implement real ray query which needs less lookups
 ray.getAABB(tmpAABB);
 tmpAABB.toLocalFrame(treeTransform, tmpAABB);
 this.aabbQuery(tmpAABB, result);
 return result;
};
/**
 * @method removeEmptyNodes
 */
OctreeNode.prototype.removeEmptyNodes = function() {
 var queue = [this];
 while (queue.length) {
 var node = queue.pop();
 for (var i = node.children.length - 1; i >= 0; i--) {
 if(!node.children[i].data.length){
 node.children.splice(i, 1);
 }
 }
 Array.prototype.push.apply(queue, node.children);
 }
};
 

AltStyle によって変換されたページ (->オリジナル) /