import { Utils } from '../common/Utils';
import { MathUtils } from '../math/MathUtils';
import { Object3D } from './Object3D';
/**
* @class BasePoints
* 基础点对象。
* @memberof THING
* @extends THING.Object3D
* @public
*/
class BasePoints extends Object3D {
/**
* 基础点对象类,负责管理点的集合和相关操作
* @param {object} param 初始化参数。
* 参数与 {@link THING.Object3D} 的构造函数相同。
* 请在 {@link THING.Object3D} 的文档中查看构造函数部分以获取详细参数列表。
*/
constructor(param = {}) {
super(param);
}
// #region 私有方法
_adjustPosition(points) {
let center = MathUtils.getCenterFromPoints(points);
this.position = center;
}
// #endregion
// #region 覆盖方法
onDestroy() {
// 清空点集引用,避免在对象销毁后还持有大量点数据导致内存泄漏
this._selfPoints = null;
super.onDestroy();
}
hasResource() {
return true;
}
onSetupResource(param) {
this._autoAdjustPosition = Utils.parseBoolean(param['autoAdjustPosition'], false);
this.onSetupPoints(param);
// Setup components
const components = param['components'];
const toolkit = param['toolkit'];
if (components && toolkit) {
this.onImportComponents(components, toolkit, param);
}
if (this.isDynamicLoad) {
return;
}
this.onLoadRenderableResource(param, () => {
this.onLoadComplete();
}, (ev) => {
if (this._loadPromise) {
this._loadPromise.reject(ev);
}
// Notify error
const onError = param['onError'] || param['error'];
onError && onError(ev);
})
}
onSetupPoints(param) {
// Setup self points
if (param['selfPoints']) {
this._selfPoints = Utils.parseValue(param['selfPoints'], []);
}
else if (param['points']) {
this._selfPoints = param['points'].map(point => {
return this.worldToSelf(point);
});
}
else {
this._selfPoints = []
}
}
onLoadRenderableResource(options, resolve, reject) {
if (this.hasResource()) {
const node = options['renderableNode'] || this.onCreateBodyNode(options);
this.onBeginSetupBodyNode(node);
this.onSetupBodyNode(node);
this.onEndSetupBodyNode(node);
this.body.setNode(node);
}
resolve && resolve();
}
onCreateBodyNode(param) {
}
// 开始设置body node 的参数
onBeginSetupBodyNode(node) {
if (!node) {
return;
}
node.begin();
}
onSetupBodyNode(node) {
const points = this.onGetSelfPoints(this._selfPoints);
node.setPoints(points);
}
// 结束设置body node 的参数
onEndSetupBodyNode(node) {
if (!node) {
return;
}
node.end();
}
onExportExternalData() {
let external = Object.assign({}, super.onExportExternalData());
Utils.setAttributeIfExist(external, 'autoAdjustPosition', this);
Utils.setAttributeIfExist(external, 'selfPoints', this);
return external;
}
onSetupPosition(param) {
if (param['localPosition'] || param['position']) {
super.onSetupPosition(param);
}
// 自动设置点集中心为线的位置
else if (param['points']) {
let center = MathUtils.getCenterFromPoints(param['points']);
this.position = center;
}
else {
super.onSetupPosition(param);
}
}
/**
* 获取自身点集回调函数。
* @param {Array<Array<number>>} selfPoints 自身点集。
* @returns {Array<Array<number>>}
* @private
*/
onGetSelfPoints(selfPoints) {
return selfPoints;
}
/**
* 设置体自身点集之前。
* @param {Array<Array<number>>} selfPoints 自身点集。
* @private
*/
onBeforeSetBodyPoints(selfPoints) {
}
/**
* 设置体自身点集之后。
* @private
*/
onAfterSetBodyPoints() {
}
// onRefresh() {
// this.onRefreshPoints();
// this.onRefreshAttributes();
// }
/**
* 刷新点集时。
* @returns {Array<Array<number>>}
* @private
*/
onRefreshPoints() {
this.onBeforeSetBodyPoints(this._selfPoints);
let selfPoints = this.onGetSelfPoints(this._selfPoints);
this.bodyNode.setPoints(selfPoints);
this.onAfterSetBodyPoints();
return selfPoints;
}
/**
* 刷新属性时。
* @private
*/
onRefreshAttributes() {
}
// #endregion
/**
* 清除所有点。
* @example
* let point = new THING.Points();
* let ret = point.points.length == 0;
* // @expect(ret == true);
* point.addPoint([1,1,1]);
* ret = point.points.length == 1;
* // @expect(ret == true);
* point.clearPoints();
* ret = point.points.length == 0;
* // @expect(ret == true);
*/
clearPoints() {
this._selfPoints = [];
this.bodyNode.setPoints([]);
}
/**
* 在世界坐标系中按索引插入点。
* @param {number} index 索引。
* @param {Array<number>} position 世界坐标位置。
* @example
* let point = new THING.Points();
* point.addPoint([1,1,1]);
* point.insertPoint(0,[10,10,10]);
* ret = point.points[0][0] == 10;
* // @expect(ret == true);
*/
insertPoint(index, position) {
let selfPoints = this._selfPoints;
selfPoints._insert(index, this.worldToSelf(position));
this.onRefreshPoints();
}
/**
* 在世界空间中添加一个点。
* @param {Array<number>} position 世界坐标位置。
* @example
* let point = new THING.Points();
* let ret = point.points.length == 0;
* // @expect(ret == true);
* point.addPoint([1,1,1]);
* ret = point.points.length == 1;
* // @expect(ret == true);
*/
addPoint(position) {
let selfPoints = this._selfPoints;
selfPoints.push(this.worldToSelf(position));
this.onRefreshPoints();
}
/**
* 在世界空间中添加多个点。
* @param {Array<Array<number>>} points 世界空间中的点。
* @example
* let point = new THING.Points();
* let ret = point.points.length == 0;
* // @expect(ret == true);
* point.addPoints([[1,1,1],[2,2,2]]);
* ret = point.points.length == 2;
* // @expect(ret == true);
*/
addPoints(points) {
let selfPoints = this._selfPoints;
points.forEach(point => {
selfPoints.push(this.worldToSelf(point));
});
this.onRefreshPoints();
}
/**
* 通过索引删除点。
* @param {number} index 索引。
* @example
* let point = new THING.Points();
* let ret = point.points.length == 0;
* // @expect(ret == true);
* point.addPoints([[1,1,1],[2,2,2]]);
* ret = point.points[0][0] == 1;
* // @expect(ret == true);
* point.removePoint(0);
* ret = point.points[0][0] == 2;
* // @expect(ret == true);
*/
removePoint(index) {
let selfPoints = this._selfPoints;
selfPoints._removeAt(index);
this.onRefreshPoints();
}
/**
* 在世界坐标系中设置指定索引的点。
* @param {number} index 索引。
* @param {Array<number>} position 世界坐标位置。
* @example
* let point = new THING.Points();
* let ret = point.points.length == 0;
* // @expect(ret == true);
* point.addPoints([[1,1,1],[2,2,2]]);
* ret = point.points[0][0] == 1;
* // @expect(ret == true);
* point.setPoint(0,[10,10,10]);
* ret = point.points[0][0] == 10;
* // @expect(ret == true);
*/
setPoint(index, position) {
let selfPoints = this._selfPoints;
selfPoints[index] = this.worldToSelf(position);
this.onRefreshPoints();
}
// #region 访问器
/**
* 点的个数
* @type {number}
* @public
* @example
* let point = new THING.Points();
* let ret = point.number == 0;
* // @expect(ret == true);
* point.addPoints([[1,1,1],[2,2,2]]);
* ret = point.number == 2;
* // @expect(ret == true);
*/
get number() {
return this.points.length;
}
/**
* 是否自动调整点坐标。当坐标过大时,由于精度问题可能导致抖动,此时需要自动调整。
* @type {boolean}
* @public
* @example
* let point = new THING.Points();
* let ret = point.autoAdjustPosition == false;
* // @expect(ret == true);
* point.autoAdjustPosition = true;
* ret = point.autoAdjustPosition == true;
* // @expect(ret == true);
*/
get autoAdjustPosition() {
return this._autoAdjustPosition;
}
set autoAdjustPosition(value) {
this._autoAdjustPosition = value;
}
/**
* 获取/设置对象自身坐标系中的点坐标集合
* @type {Array<Array<number>>}
* @public
* @example
* let point = new THING.Points();
* point.selfPoints = [[1,1,1],[2,2,2]];
* ret = point.selfPoints[1][1] == 2;
* // @expect(ret == true);
*/
get selfPoints() {
return this._selfPoints;
}
set selfPoints(value) {
this._selfPoints = value ? value.slice(0) : [];
this.onRefreshPoints();
}
/**
* 获取/设置世界坐标系中的点坐标集合
* @type {Array<Array<number>>}
* @public
* @example
* let point = new THING.Points();
* point.points = [[1,1,1],[2,2,2]];
* ret = point.points[1][1] == 2;
* // @expect(ret == true);
*/
get points() {
return this._selfPoints.map(point => {
return this.selfToWorld(point);
});
}
set points(value) {
if (value) {
if (this._autoAdjustPosition) {
this._adjustPosition(value);
}
this._selfPoints = value.map(point => {
return this.worldToSelf(point);
});
this.onRefreshPoints();
}
else {
this.clearPoints();
}
}
/**
* 获取/设置局部坐标系中的点坐标集合
* @type {Array<Array<number>>}
* @public
* @example
* let point = new THING.Points();
* point.localPoints = [[1,1,1],[2,2,2]];
* ret = point.localPoints[1][1] == 2;
* // @expect(ret == true);
*/
get localPoints() {
return this._selfPoints.map(point => {
return this.selfToLocal(point);
});
}
set localPoints(value) {
if (value) {
this._selfPoints = value.map(point => {
return this.localToSelf(point);
});
this.onRefreshPoints();
}
else {
this.clearPoints();
}
}
/**
* 获取由点形成的路径的长度
* @type {number}
* @public
* @example
* let point = new THING.Points();
* point.localPoints = [[0,0,0],[3,0,0],[0,4,0]];
* ret = point.length == 8;
* // @expect(ret == true);
*/
get length() {
return MathUtils.getDistanceFromPoints(this.points);
}
// #endregion
}
export { BasePoints }