Source: objects/Space3D.js

import { MathUtils } from '../math/MathUtils';
import { Object3D } from './Object3D';
import { Utils } from '../common/Utils';
import { SpaceRelationComponent } from '../components/SpaceRelationComponent';
import { SpaceHelperComponent } from '../components/SpaceHelperComponent';

const __ = {
	private: Symbol('private'),
}

const relation = {
	contains: 'contains',
	intersects: 'intersects',
	disjoint: 'disjoint'
}

const registerComponentParam = { isResident: true };

/**
 * @class Space3D
 * The space3D object.
 * @memberof THING
 * @extends THING.Object3D
 * @public
 */
class Space3D extends Object3D {

	static defaultTagArray = ['Space3D'];

	/**
	 * The space3D object.
	 * @param {Object} param The initial parameters.
	 */
	constructor(param = {}) {
		super(param);

		this[__.private] = {};
		let _private = this[__.private];

		_private.size = param['size'];

		// init local bounding box
		if (_private.size) {
			this.initialLocalBoundingBox = {
				center: [0, 0, 0],
				halfSize: MathUtils.divideVector(_private.size, 2)
			};
		}
	}

	clearInitialLocalBoundingBox() { }

	onSetupComponent(param) {
		super.onSetupComponent(param);

		this.addComponent(SpaceRelationComponent, 'spaceCalculation', registerComponentParam);
		this.addComponent(SpaceHelperComponent, 'spaceHelper', registerComponentParam);
	}

	/**
	 * contains relation
	 * @param {Object} obj THe relation object.
	 * @param {Boolean} cascade The cascade.
	 * @returns {Boolean}
	 * @example
	 * 	let result = this.contains(obj, false);
	 *  console.log(result);
	 * @public
	 */
	contains(obj, cascade = true) {
		return this._calcRelationByCondition(obj, cascade, relation.contains);
	}

	/**
	 * intersects relation
	 * @param {Object} obj THe relation object.
	 * @param {Boolean} cascade The cascade.
	 * @returns {Boolean}
	 * @example
	 * 	let result = this.intersects(obj, false);
	 *  console.log(result);
	 * @public
	 */
	intersects(obj, cascade = true) {
		return this._calcRelationByCondition(obj, cascade, relation.intersects);
	}

	/**
	 * disjoint relation
	 * @param {Object} obj THe relation object.
	 * @param {Boolean} cascade The cascade.
	 * @returns {Boolean}
	 * @example
	 * 	let result = this.disjoint(obj, false);
	 *  console.log(result);
	 * @public
	 */
	disjoint(obj, cascade = true) {
		return this._calcRelationByCondition(obj, cascade, relation.disjoint);
	}

	/**
	 * show bounding
	 * @param {Boolean} value The value, default is true.
	 * @example
	 * 	space.showBounding();
	 * @public
	 */
	showBounding(value = true) {
		let _private = this[__.private];

		if (!_private.size && !this.children.length) {
			Utils.warn('Space3D no size!');
			return;
		}

		this.traverse((object) => {
			if (object.isSpace3D && object.size) {
				object.spaceHelper.showBounding(value);
			}
		});
	}

	// calc relation by condition
	_calcRelationByCondition(obj, cascade, condition) {
		let spaces = [];
		this.traverse((object) => {
			if (object.isSpace3D && object.size) {
				spaces.push(object);
			}
		});

		switch (condition) {
			case relation.contains:
			case relation.intersects:
				return _calcRelation(true);
			case relation.disjoint:
				return _calcRelation(false);
		}

		function _calcRelation(bool) {
			for (let i = 0; i < spaces.length; i++) {
				const space = spaces[i];

				if (space.spaceCalculation[condition](obj, cascade) === bool) {
					return bool;
				}
			}

			return !bool;
		}
	}

	/**
	 * The object size
	 * @type {Array<Number>}
	 */
	get size() {
		let _private = this[__.private];

		return _private.size;
	}

	/**
	 * Check whether it's Space3D type or inherit from it.
	 * @type {Boolean}
	 */
	get isSpace3D() {
		return true;
	}

}

export { Space3D }