import { Utils } from './Utils'
import { BoundingSphere } from './BoundingSphere';
import { MathUtils } from '../math/MathUtils'
let _vec3 = MathUtils.createVec3();
/**
* @class Box3
* 表示具有[min, max]的盒子。
* @memberof THING
* @public
*/
class Box3 {
/**
* 盒子类构造函数。
* @param {object} param 构造参数。
* @param {Array} param.center 盒子中心坐标。
* @param {Array} param.halfSize 盒子半尺寸。
*/
constructor(center, halfSize) {
this._min = [+Infinity, +Infinity, +Infinity];
this._max = [-Infinity, -Infinity, -Infinity];
this.set(center, halfSize);
}
// #region Private
_getPoints(min, max, result) {
result = result || [];
// TOP
result[0] = [min[0], min[1], min[2]];
result[1] = [max[0], min[1], min[2]];
result[2] = [max[0], min[1], max[2]];
result[3] = [min[0], min[1], max[2]];
// BOTTOM
result[4] = [min[0], max[1], min[2]];
result[5] = [max[0], max[1], min[2]];
result[6] = [max[0], max[1], max[2]];
result[7] = [min[0], max[1], max[2]];
return result;
}
// Get the layout position from box
_getLayoutPosition(types, min, max) {
if (Utils.getArrayLength(types) !== 3) {
return null;
}
let points = this._getPoints(min, max);
let lines = [
[points[0], points[1]], // X
[points[0], points[4]], // Y
[points[0], points[2]], // Z
];
let progress = [
Utils.getProgressByLayout(types[0]),
Utils.getProgressByLayout(types[1]),
Utils.getProgressByLayout(types[2]),
];
let x = MathUtils.lerpVector(lines[0][0], lines[0][1], progress[0])[0];
let y = MathUtils.lerpVector(lines[1][0], lines[1][1], progress[1])[1];
let z = MathUtils.lerpVector(lines[2][0], lines[2][1], progress[2])[2];
return [x, y, z];
}
// #endregion
isEmpty() {
return (this._max[0] < this._min[0]) || (this._max[1] < this._min[1]) || (this._max[2] < this._min[2]);
}
makeEmpty() {
this._min = [+Infinity, +Infinity, +Infinity];
this._max = [-Infinity, -Infinity, -Infinity];
return this;
}
set(center, halfSize) {
if (center && halfSize) {
MathUtils.vec3.sub(this._min, center, halfSize);
MathUtils.vec3.add(this._max, center, halfSize);
}
return this;
}
expandByPoint(point) {
MathUtils.vec3.min(this._min, this._min, point);
MathUtils.vec3.max(this._max, this._max, point);
return this;
}
getBoundingSphere(boundingSphere = new BoundingSphere()) {
boundingSphere.set(this.center, this.radius);
return boundingSphere;
}
getPoints() {
return this._getPoints(this.min, this.max);
}
getLayoutPosition(types) {
return this._getLayoutPosition(types, this.min, this.max);
}
/**
* 获取最小位置。
* @type {Array<number>}
* @example
* // 打印盒子的最小位置。
* console.log(box.min);
* @public
*/
get min() {
return this._min.slice(0);
}
/**
* 获取最大位置。
* @type {Array<number>}
* @example
* // 打印盒子的最大位置。
* console.log(box.max);
* @public
*/
get max() {
return this._max.slice(0);
}
/**
* 获取中心位置。
* @type {Array<number>}
* @example
* let box = new THING.Box3([10, 20, 40], [2, 3, 4]);
* let center = box.boundingBox.center;
* // @expect(center[0] == 10);
* // @expect(center[1] == 20);
* // @expect(center[2] == 40);
* @public
*/
get center() {
return this.isEmpty() ? [0, 0, 0] : MathUtils.vec3.scale([], MathUtils.vec3.add(_vec3, this._min, this._max), 0.5);
}
/**
* 获取尺寸的一半
* @type {Array<number>}
* @example
* let box = new THING.Box3([10, 20, 40], [2, 3, 4]);
* let halfSize = box.halfSize;
* // @expect(halfSize[0] == 2);
* // @expect(halfSize[1] == 3);
* // @expect(halfSize[2] == 4);
* @public
*/
get halfSize() {
let size = this.size;
return MathUtils.vec3.scale(size, size, 0.5);
}
/**
* 获取尺寸
* @type {Array<number>}
* @example
* let box = new THING.Box3([10, 20, 40], [2, 3, 4]);
* let size = box.size;
* // @expect(size[0] == 4);
* // @expect(size[1] == 6);
* // @expect(size[2] == 8);
* @public
*/
get size() {
return this.isEmpty() ? [0, 0, 0] : MathUtils.vec3.sub([], this._max, this._min);
}
/**
* 获取半径
* @type {number}
* @example
* // 创建一个盒子并获取其半径
* let box = new THING.Box3([10, 20, 30], [5, 5, 5]);
* let radius = box.radius;
* // 半径应该是盒子对角线长度的一半
* console.log(radius); // 约为 8.66
* @public
*/
get radius() {
let size = this.size;
return Math.sqrt((Math.pow(size[0], 2) + Math.pow(size[1], 2) + Math.pow(size[2], 2))) / 2;
}
get isBox3() {
return true;
}
}
export { Box3 }