import { Utils } from '../common/Utils';
import { ObjectBoxHelper } from '../helpers/ObjectBoxHelper';
import { ObjectOrientedBoxHelper } from '../helpers/ObjectOrientedBoxHelper';
import { BaseComponent } from './BaseComponent';
import { BoxHelperModeType } from '../const';
const __ = {
private: Symbol('private'),
}
/**
* @class HelperComponent
* The object helper component.
* @memberof THING
* @extends THING.BaseComponent
* @public
*/
class HelperComponent extends BaseComponent {
static mustCopyWithInstance = true;
/**
* The helper component of object what can show many useful information of it, like axis, bounding box, etc.
*/
constructor() {
super();
this[__.private] = {};
let _private = this[__.private];
_private.helpers = {
axes: null,
boundingBox: null,
orientedBox: null,
};
_private.axesLength = 0;
_private.boundingBox = null;
_private.orientedBox = null;
}
// #region Private
_enableLineHelper(name, value, onGetPoints, onGetColors) {
let _private = this[__.private];
if (value) {
if (_private.helpers[name]) {
return;
}
let object = this.object;
object.waitForComplete().then(() => {
let lineSegments = Utils.createObject('LineSegments');
lineSegments.setAttribute('Pickable', false);
lineSegments.getUserData()['isDebugNode'] = true;
object.body.createRootNode();
object.node.add(lineSegments);
let points = onGetPoints();
let colors = onGetColors();
lineSegments.setSize(points.length * 3);
lineSegments.setPoints(points);
lineSegments.setColors(colors);
_private.helpers[name] = lineSegments;
});
}
else {
if (!_private.helpers[name]) {
return;
}
_private.helpers[name].dispose();
_private.helpers[name] = null;
}
}
_enableBoxHelper(type, name, value, callback) {
let _private = this[__.private];
if (value) {
if (!_private.helpers[name]) {
_private.helpers[name] = new type({ object: this.object });
this.app.scene.rootObjects['debug'].node.add(_private.helpers[name].lines);
}
callback(_private.helpers[name]);
}
else {
if (!_private.helpers[name]) {
return;
}
_private.helpers[name].dispose();
_private.helpers[name] = null;
}
}
_refreshBoxHelper(type, name, visible, mode, color) {
this._enableBoxHelper(type, name, visible, (helper) => {
helper.mode = mode;
helper.color = color;
});
}
_createBoxHelper(type, name) {
let that = this;
let visible = false;
let mode = BoxHelperModeType.All;
let color = [1, 1, 1];
let object = {};
Object.defineProperties(object, {
'visible': {
get: function () {
return visible;
},
set: function (value) {
visible = value;
that._refreshBoxHelper(type, name, visible, mode, color);
}
},
'mode': {
get: function () {
return mode;
},
set: function (value) {
mode = value;
that._refreshBoxHelper(type, name, visible, mode, color);
}
},
'color': {
get: function () {
return color;
},
set: function (value) {
color = Utils.parseColor(value, [1, 1, 1]);
that._refreshBoxHelper(type, name, visible, mode, color);
}
}
});
return object;
}
_show(visible) {
let _private = this[__.private];
let helpers = _private.helpers;
for (let key in helpers) {
if (helpers[key]) {
helpers[key].setVisible(visible);
}
}
}
// #endregion
// #region BaseComponent Interface
onRemove() {
let _private = this[__.private];
let helpers = _private.helpers;
for (let key in helpers) {
if (helpers[key]) {
helpers[key].dispose();
helpers[key] = null;
}
}
super.onRemove();
}
onVisibleChange(value) {
this._show(value);
}
// #endregion
// #region Accessors
/**
* @typedef {Object} BoxHelperResult
* @property {Boolean} visible The visible state.
* @property {Array<Number>} color The color.
* @property {BoxHelperModeType} mode The mode.
*/
/**
* Get bounding box.
* @type {BoxHelperResult}
* @example
* let component = new THING.HelperComponent();
* let bounding = component.boundingBox;
* // @expect(bounding.mode == 'All')
* @public
*/
get boundingBox() {
let _private = this[__.private];
if (!_private.boundingBox) {
_private.boundingBox = this._createBoxHelper(ObjectBoxHelper, 'boundingBox');
}
return _private.boundingBox;
}
/**
* Get oriented box.
* @type {BoxHelperResult}
* @example
* let component = new THING.HelperComponent();
* let bounding = component.orientedBox;
* // @expect(bounding.mode == 'All')
* @public
*/
get orientedBox() {
let _private = this[__.private];
if (!_private.orientedBox) {
_private.orientedBox = this._createBoxHelper(ObjectOrientedBoxHelper, 'orientedBox');
}
return _private.orientedBox;
}
/**
* Show/Hide axes helper.
* @type {Boolean}
* @example
* let box = new THING.Box();
* box.helper.axes = true;
* box.waitForComplete().then(()=>{
* let ret = box.helper.axes;
* // @expect(ret == true);
* })
* @public
*/
get axes() {
let _private = this[__.private];
return !!_private.helpers['axes'];
}
set axes(value) {
let _private = this[__.private];
this._enableLineHelper('axes', value,
() => {
let size = _private.axesLength;
if (!size) {
size = this.object.boundingBox.halfSize.reduce((total, num) => {
return total + num;
}, 0);
}
// Make sure we can see it
size = Math.max(size, 10);
_private.axesLength = size;
return [
[0, 0, 0], [size, 0, 0],
[0, 0, 0], [0, size, 0],
[0, 0, 0], [0, 0, size]
];
},
() => {
return [
[1, 0, 0], [1, 0.6, 0],
[0, 1, 0], [0.6, 1, 0],
[0, 0, 1], [0, 0.6, 1]
];
}
);
}
/**
* Get/Set axes helper length.
* @type {Number}
* @example
* let box = new THING.Box();
* box.helper.axesLength = 10;
* // @expect(box.helper.axesLength == 10);
* @public
*/
get axesLength() {
let _private = this[__.private];
return _private.axesLength;
}
set axesLength(value) {
let _private = this[__.private];
_private.axesLength = value;
this.object.waitForComplete().then(() => {
// Refresh axes
let axes = _private.helpers.axes;
if (axes) {
axes.setPoints([
[0, 0, 0], [value, 0, 0],
[0, 0, 0], [0, value, 0],
[0, 0, 0], [0, 0, value]
]);
}
});
}
/**
* Get the light(s)'s config.
* @type {Array<Object>}
* @example
* let box = new THING.Box();
* let count = box.helper.lights.length;
* // @expect(count == 0);
* @public
*/
get lights() {
return this.object.query('.Light').map(light => {
let object = {
type: light.type,
id: light.id,
name: light.name,
uuid: light.uuid,
};
[
'color',
'intensity',
'angles',
'components',
].forEach(name => {
Utils.bindObjectProperty(object, light, name);
});
if (light.isBaseShadowLight) {
[
'castShadow',
'shadowQuality',
'shadowBias',
'shadowRadius',
'shadowRange',
].forEach(name => {
Utils.bindObjectProperty(object, light, name);
});
}
if (light.isSpotLight) {
[
'distance',
'angle',
'penumbra',
'decay',
].forEach(name => {
Utils.bindObjectProperty(object, light, name);
});
}
else if (light.isHemisphereLight) {
[
'groundColor',
].forEach(name => {
Utils.bindObjectProperty(object, light, name);
});
}
return object;
}).toArray();
}
// #endregion
}
export { HelperComponent }