import { Object3D, BaseComponent, MeshBuilder, MathUtils, Box, Sphere, Mesh, FatLine, PlaneRegion } from '@uino/thing';

/**
 * TransformControlComponent 物体变换组件
 * @class
 * @summary 提供物体变换的功能,变换模式包括平移、旋转和缩放三种,坐标系变换包括世界坐标系和本地坐标系两种。
 * 注意:不能跟拖拽组件(DragComponent)或物体拖拽组件(DragControlComponent)同时使用。
 * 可通过组件所依附的对象注册变换事件,object.on('TRANSFORM_CONTROL_UPDATE',()=>{ console.log('change') })
 * @extends {THING.BaseComponent}
 * @memberof THING
 * @example
 *  var app = new THING.App();
 *	var gui = new dat.GUI();
 *
 *	app.camera.position = [20,20,20];
 *	app.background = [0.5, 0.5, 0.5];
 *    
 *	for (let i = 0; i < 5; i++) {
 *		const name = 'box' + i;
 *		window[name] = new THING.Box(2,2,2);
 *		window[name].position = [-10 + i * 4, 0, 0]
 *	}
 *
 *	const component = new THING.EXTEND.TransformControlComponent();
 *    
 *	// 创建一个空对象,通过setObjects给多个对象添加组件
 *	window.emptyObject = new THING.Object3D();
 *	emptyObject.addComponent(component,'transformControlComponent');
 *	emptyObject.transformControlComponent.setObjects([box0, box1, box3])
 *
 *	// 监听物体变换组件更新事件
 *	emptyObject.on('TRANSFORM_CONTROL_UPDATE', () => {
 *		console.warn('update');
 *	});
 *
 *	const transformation = [
 *		'translate',
 *		'angle',
 *		'scale'
 *	];
 *	const coordinate = [
 *		'worldCoordinate',
 *		'localCoordinate'
 *	];
 *
 *	const dataObj = {
 *		Coordinate:coordinate[0],
 *		Transformation:transformation[0],
 *		Snap:0,
 *		KeepSize:false,
 *		Size:1
 *	};
 *
 *	gui.add(dataObj, 'Coordinate',coordinate).onChange(function(){
 *		if(dataObj.Coordinate === 'worldCoordinate'){
 *			emptyObject.transformControlComponent.space = 'world';
 *		}else if(dataObj.Coordinate === 'localCoordinate'){
 *			emptyObject.transformControlComponent.space = 'local';
 *		}
 *	});
 *
 *	gui.add(dataObj, 'Transformation',transformation).onChange(function(){
 *		if(dataObj.Transformation === 'translate'){
 *			emptyObject.transformControlComponent.mode = 'translate';
 *		}else if(dataObj.Transformation === 'angle'){
 *			emptyObject.transformControlComponent.mode = 'angle';
 *		}else if(dataObj.Transformation === 'scale'){
 *			emptyObject.transformControlComponent.mode = 'scale';
 *		}
 *	});
 *
 *	gui.add(dataObj,'Snap',0, 45).step(0.1).onChange(function(e){
 *		emptyObject.transformControlComponent.snap = dataObj.Snap;
 *	});
 *
 *	let factor = gui.addFolder('factor');
 *	factor.add(dataObj,'KeepSize').onChange(function(e){
 *		emptyObject.transformControlComponent.keepSize = dataObj.KeepSize;
 *	});
 *
 *	factor.add(dataObj,'Size',0.1, 10).step(0.1).onChange(function(e){
 *		emptyObject.transformControlComponent.size = dataObj.Size;
 *	});
 * @public
 */
class TransformControlComponent extends BaseComponent {

	static isInstancedComponent = true;

	/**
	 * 变换控制组件类构造函数,用于实现物体变换的功能。
	 * @param {object} param 参数列表
	 */
	constructor(param) {
		super(param);

		this._configData = {
			"AxisX": [1, 0, 0],
			"AxisY": [0, 1, 0],
			"AxisZ": [0, 0, 1],
			"AxisXY": [1, 1, 0],
			"AxisYZ": [0, 1, 1],
			"AxisXZ": [1, 0, 1],
			"AxisXYZ": [1, 1, 1],
			"anglesX": [1, 0, 0],
			"anglesY": [0, 1, 0],
			"anglesZ": [0, 0, 1],
			"anglesXYZ": [1, 1, 1],
			"ScaleX": [1, 0, 0],
			"ScaleY": [0, 1, 0],
			"ScaleZ": [0, 0, 1],
			"ScaleXYZ": [1, 1, 1]
		}
		this._intersection = [];
		this._objHelpers = [];
		this._plane = { normal: [], constant: 0 };
		this._raycaster = { origin: [], direction: [] };
		this._mouse = [];
		this._offset = [];
		this._selected = null;
		this._scaleData = [];
		this._newVariety = [];
		this._statsData = [];
		this._startPoint = [];
		this._objectPoint = [];
		this._objQuaterStart = [];
		this._helperCurrentColor = null;
		this._isEnterDown = false;
		this._downName = null;
		this._jd = 0;
		this._objCurrentQuaterEng = null;
		this._helperParentObj = null;

		this._objAngleQuaternionX = [];
		this._objAngleQuaternionY = [];
		this._objAngleQuaternionZ = [];

		this._space = 'world'; // world,local
		this._mode = 'translate'; // translate, rotate, scale
		this._snap = 0;
		this._keepSize = true;
		this._size = 1;

		this._objMap = {};
		this._emptyObjects = [];
		
		// 新增:轴锁定功能
		this._lockedAxes = { x: false, y: false, z: false }; // 锁定的轴
	}

	onAdd(object) {
		super.onAdd(object);

		// 总是创建helper,确保轴锁定功能正常工作
		this._createHelperAxis();

		this._enterLevelEvent();
		this._dragEvent();
	}

	onActiveChange(value) {
		if (this._helperParentObj) {
			this._helperParentObj.setActive(value, true);
		}
	}

	onVisibleChange(value) {
		if (this.object.active) {
			if (this._helperParentObj) {
				this._helperParentObj.setVisible(value, true);
			}
		}
	}

	onRemove() {
		this.object.app.off('mouseenter', 'TransformControlComponentEnterEnter');
		this.object.app.off('mouseleave', 'TransformControlComponentEnterLeave');
		this.object.app.off('mousedown', 'TransformControlComponentEnterDown');
		this.object.app.off('mouseup', 'TransformControlComponentEnterUp');

		this.object.app.off('mousedown', 'TransformControlComponentDragDown');
		this.object.app.off('mousemove', 'TransformControlComponentDragMove');
		this.object.app.off('mouseup', 'TransformControlComponentDragUp');
		this._destroys();

		super.onRemove();
	}

	onUpdate() {
		if (this._keepSize) {
			let dis = MathUtils.sqrt(MathUtils.getDistanceToSquared(this.object.position, this.object.app.camera.position));
			let axisFactor = dis * MathUtils.min(1.9 * MathUtils.tan(MathUtils.PI * this.object.app.camera.fov / 360), 7);
			this._helperParentObj.scale =
				[
					axisFactor / 15 * this._size,
					axisFactor / 15 * this._size,
					axisFactor / 15 * this._size
				];
		}
		if (this._helperParentObj) {
			this._helperParentObj.position = this.object.position;

			if (this._space === 'local' || this._mode === 'scale') {
				this._helperParentObj.quaternion = this.object.quaternion;
			}
		}

		if (this._mode === 'rotate') {
			let eye = MathUtils.normalizeVector(MathUtils.subVector(this.object.app.camera.position, this._helperParentObj.position));
			let alignVector = MathUtils.vec3ApplyQuat(eye, this._invert(this._helperParentObj.quaternion));

			this._updateAngleAxis('anglesX', [1, 0, 0], [-alignVector[1], alignVector[2]], this._objAngleQuaternionX)
			this._updateAngleAxis('anglesY', [0, 1, 0], [alignVector[0], alignVector[2]], this._objAngleQuaternionY)
			this._updateAngleAxis('anglesZ', [0, 0, 1], [alignVector[1], alignVector[0]], this._objAngleQuaternionZ)
		}
	}

	_updateAngleAxis(objName, dir, eyeDir, angleQuaternion) {
		const obj = this._helperParentObj.children.query(objName)[0];
		if (!obj) { return; }
		let eyeQuaternion = MathUtils.getQuatFromAxisAngle(dir, MathUtils.radToDeg(MathUtils.atan2(eyeDir[0], eyeDir[1])));
		if (this._space === 'local') {
			let initialQuaternion = this._helperParentObj.quaternion;
			let currentQuaternion = MathUtils.multiplyQuat(eyeQuaternion, angleQuaternion);
			obj.quaternion = MathUtils.multiplyQuat(initialQuaternion, currentQuaternion);
		}
		else {
			obj.quaternion = MathUtils.multiplyQuat(eyeQuaternion, angleQuaternion);
		}
	}

	_createHelperAxis() {
		this._destroys();
		this._helperParentObj = new Object3D();
		this._helperParentObj.active = !!this._objMap && Object.keys(this._objMap).length > 0;

		if (this._mode === 'translate') {
			// 根据轴锁定状态创建helper
			if (!this._lockedAxes.x) {
				this._createAxisLine([0, 0, 0], [0, 0, 0, 1], [1, 1, 1], 'red', false, 'AxisX');
				this._createAxisCone([2, 0, 0], [0, 0, -0.7071067811865475, 0.7071067811865476], [1, 1, 1], 'red', false, 'AxisX');
			}

			if (!this._lockedAxes.y) {
				this._createAxisLine([0, 0, 0], [0, 0, 0.7071067811865475, 0.7071067811865476], [1, 1, 1], 'green', false, 'AxisY');
				this._createAxisCone([0, 2, 0], [0, 0, 0, 1], [1, 1, 1], 'green', false, 'AxisY');
			}

			if (!this._lockedAxes.z) {
				this._createAxisLine([0, 0, 0], [0, -0.7071067811865475, 0, 0.7071067811865476], [1, 1, 1], 'blue', false, 'AxisZ');
				this._createAxisCone([0, 0, 2], [0.7071067811865475, 0, 0, 0.7071067811865476], [1, 1, 1], 'blue', false, 'AxisZ');
			}

			// 平面helper - 只有当对应的轴都未锁定时才显示
			if (!this._lockedAxes.x && !this._lockedAxes.y) {
				this._createAxisPlane([0.3, 0.3, 0], [-0.7071067811865475, 0, 0, 0.7071067811865476], [1, 1, 1], 'blue', false, 'AxisXY');
			}

			if (!this._lockedAxes.y && !this._lockedAxes.z) {
				this._createAxisPlane([0, 0.3, 0.3], [0, 0, 0.7071067811865475, 0.7071067811865476], [1, 1, 1], 'red', false, 'AxisYZ');
			}

			if (!this._lockedAxes.x && !this._lockedAxes.z) {
				this._createAxisPlane([0.3, 0, 0.3], [0, 0, 0, 1], [1, 1, 1], 'green', false, 'AxisXZ');
			}

			// 中心球 - 只有当所有轴都未锁定时才显示
			if (!this._lockedAxes.x && !this._lockedAxes.y && !this._lockedAxes.z) {
				this._createAxisCenter([0, 0, 0], [0, 0, 0, 1], [1, 1, 1], 'black', false, 'AxisXYZ');
			}
		}
		else if (this._mode === 'rotate') {
			// 旋转模式下的轴控制
			if (!this._lockedAxes.x) {
				this._createAxisCircle([0, 0, 0], [0.5, 0.5, 0.5, 0.5], [1, 1, 1], 'red', false, 'anglesX', 0.5);
			}

			if (!this._lockedAxes.y) {
				this._createAxisCircle([0, 0, 0], [0.7071067811865475, 0, 0, 0.7071067811865476], [1, 1, 1], 'green', false, 'anglesY', 0.5);
			}

			if (!this._lockedAxes.z) {
				this._createAxisCircle([0, 0, 0], [0, 0, 0.7071067811865476, -0.7071067811865476], [1, 1, 1], 'blue', false, 'anglesZ', 0.5);
			}

			// 多轴旋转 - 只有当对应的轴都未锁定时才显示
			if (!this._lockedAxes.x && !this._lockedAxes.y && !this._lockedAxes.z) {
				this._createAxisCircle([0, 0, 0], [0, 0, 0, 1], [1.5, 1.5, 1], 'cyan', false, 'anglesXYZ', 1);
				this._createAxisCircle([0, 0, 0], [0, 0, 0, 1], [1, 1, 1], '0x787878', false, 'anglesXYZE', 1);
			}
		}
		else if (this._mode === 'scale') {
			// 缩放模式下的轴控制
			if (!this._lockedAxes.x) {
				this._createAxisLine([0, 0, 0], [0, 0, 0, 1], [1, 1, 1], 'red', false, 'ScaleX');
				this._createScaleBox([2, 0, 0], [0, 0, 0, 1], [1, 1, 1], 'red', false, 'ScaleX');
			}

			if (!this._lockedAxes.y) {
				this._createAxisLine([0, 0, 0], [0, 0, 0.7071067811865475, 0.7071067811865476], [1, 1, 1], 'green', false, 'ScaleY');
				this._createScaleBox([0, 2, 0], [0, 0, 0, 1], [1, 1, 1], 'green', false, 'ScaleY');
			}

			if (!this._lockedAxes.z) {
				this._createAxisLine([0, 0, 0], [0, -0.7071067811865475, 0, 0.7071067811865476], [1, 1, 1], 'blue', false, 'ScaleZ');
				this._createScaleBox([0, 0, 2], [0, 0, 0, 1], [1, 1, 1], 'blue', false, 'ScaleZ');
			}

			// 平面缩放 - 只有当对应的轴都未锁定时才显示
			if (!this._lockedAxes.x && !this._lockedAxes.y) {
				this._createAxisPlane([0.3, 0.3, 0], [-0.7071067811865475, 0, 0, 0.7071067811865476], [1, 1, 1], 'blue', false, 'AxisXY');
			}

			if (!this._lockedAxes.y && !this._lockedAxes.z) {
				this._createAxisPlane([0, 0.3, 0.3], [0, 0, 0.7071067811865475, 0.7071067811865476], [1, 1, 1], 'red', false, 'AxisYZ');
			}

			if (!this._lockedAxes.x && !this._lockedAxes.z) {
				this._createAxisPlane([0.3, 0, 0.3], [0, 0, 0, 1], [1, 1, 1], 'green', false, 'AxisXZ');
			}

			// 整体缩放 - 只有当所有轴都未锁定时才显示
			if (!this._lockedAxes.x && !this._lockedAxes.y && !this._lockedAxes.z) {
				this._createScaleBox([0, 0, 0], [0, 0, 0, 1], [1, 1, 1], 'black', false, 'ScaleXYZ');
			}
		}
	}

	_enterLevelEvent() {
		let that = this;
		let app = this.object.app;
		app.on('mouseenter', function (ev) {
			if (that._objHelpers.includes(ev.object)) {
				if (!that._isEnterDown) {
					if (!that._helperCurrentColor) { that._helperCurrentColor = ev.object.style.color.slice(); }
					that.object.app.query(ev.object.name).style.color = 'pink';
				}
			}
		}, 'TransformControlComponentEnterEnter');
		app.on('mouseleave', function (ev) {
			if (!that._isEnterDown) {
				if (that._objHelpers.includes(ev.object)) {
					if (that._helperCurrentColor) {
						that.object.app.query(ev.object.name).style.color = that._helperCurrentColor;
						that._helperCurrentColor = null;
					}
				}
			}
		}, 'TransformControlComponentEnterLeave');
		app.on('mousedown', function (ev) {
			if (that._objHelpers.includes(ev.object)) {
				that._isEnterDown = true;
				that._downName = ev.object.name;
			}
		}, 'TransformControlComponentEnterDown');
		app.on('mouseup', function () {
			if (that._helperCurrentColor) {
				that.object.app.query(that._downName).style.color = that._helperCurrentColor;
			}
			that._isEnterDown = false;
			that._helperCurrentColor = null;
			that._downName = null;
		}, 'TransformControlComponentEnterUp');
	}

	_dragEvent() {
		let app = this.object.app;
		let that = this;
		app.on("mousedown", function (ev) {
			if (!that._objHelpers.includes(ev.object)) { return; }
			app.camera.control.enable = false;
			that._selected = ev.object;

			that._plane.normal = app.camera.transform.getForward();
			that._plane.constant = -MathUtils.dotVector(that._plane.normal, ev.object.position);
			that._mouse = app.camera.screenToWorld([ev.x, ev.y, 0]);

			if (app.camera.projectionType === 'Orthographic') {
				that._raycaster.origin = app.camera.screenToWorld([ev.x, ev.y,
				(app.camera.near + app.camera.far) / (app.camera.near - app.camera.far)]);
				that._raycaster.direction = MathUtils.transformDirection([0, 0, -1], app.camera.matrixWorld);
			}
			else {
				that._raycaster.origin = app.camera.position;
				that._raycaster.direction = MathUtils.normalizeVector(MathUtils.subVector(that._mouse, app.camera.position));
			}
			that._intersection = app.camera.intersectPlane(ev.x, ev.y, that._plane.normal, that._plane.constant);
			if (that._intersection) {
				that._objectPoint = that.object.position;
				that._startPoint = MathUtils.subVector(that._intersection, that._objectPoint);
				that._objQuaterStart = that.object.quaternion;

				that._offset = MathUtils.subVector(that._intersection, that._objectPoint);
				that._scaleData = that.object.scale;
				if (that._mode === 'scale') {
					that._offset = MathUtils.addVector(that._offset, that.object.position)
				}
			}
		}, 'TransformControlComponentDragDown');

		app.on("mousemove", function (ev) {
			if (that._selected) {
				that._mouse = app.camera.screenToWorld([ev.x, ev.y, 0]);
				that._plane.normal = app.camera.transform.getForward();
				that._plane.constant = -MathUtils.dotVector(that._plane.normal, that._selected.position);

				if (app.camera.projectionType === 'Orthographic') {
					that._raycaster.origin = app.camera.screenToWorld([ev.x, ev.y,
					(app.camera.near + app.camera.far) / (app.camera.near - app.camera.far)]);
					that._raycaster.direction = MathUtils.transformDirection([0, 0, -1], app.camera.matrixWorld);
				}
				else {
					that._raycaster.origin = app.camera.position;
					that._raycaster.direction = MathUtils.normalizeVector(MathUtils.subVector(that._mouse, app.camera.position));
				}

				that._statsData = that._configData[that._selected.name];

				that._intersection = app.camera.intersectPlane(ev.x, ev.y, that._plane.normal, that._plane.constant);
				if (that._intersection) {
					that._intersection = MathUtils.subVector(that._intersection, that._objectPoint);
					if (that._mode === 'translate') {
						that._turnTranslate();
					}
					else if (that._mode === 'rotate') {
						that._turnAngle();
					}
					else if (that._mode === 'scale') {
						that._turnScale();
					}
				}
			}
		}, 'TransformControlComponentDragMove');

		app.on("mouseup", function () {
			app.camera.control.enable = true;
			that._selected = null;
			this._jd = 0;
		}, 'TransformControlComponentDragUp');
	}

	_turnTranslate() {
		// 应用轴锁定
		let effectiveStatsData = [...this._statsData];
		if (this._lockedAxes.x) effectiveStatsData[0] = 0;
		if (this._lockedAxes.y) effectiveStatsData[1] = 0;
		if (this._lockedAxes.z) effectiveStatsData[2] = 0;

		for (let i = 0; i < 3; i++) {
			let temp = (this._intersection[i] - this._offset[i]);
			let snapPos = this._snap > 0 ? temp - (temp % this._snap) : temp;
			this._newVariety[i] = (effectiveStatsData[i] ? this._objectPoint[i] + snapPos : this._objectPoint[i]);
		}

		if (this._space === 'local') {
			let offs = MathUtils.subVector(this._intersection, this._startPoint);
			let nowVec3x = MathUtils.vec3ApplyQuat([1, 0, 0], this._objQuaterStart);
			let newX = MathUtils.dotVector(offs, nowVec3x);

			let nowVec3y = MathUtils.vec3ApplyQuat([0, 1, 0], this._objQuaterStart);
			let newY = MathUtils.dotVector(offs, nowVec3y);

			let nowVec3z = MathUtils.vec3ApplyQuat([0, 0, 1], this._objQuaterStart);
			let newZ = MathUtils.dotVector(offs, nowVec3z);

			if (this._selected.name.indexOf('X') === -1) newX = 0;
			if (this._selected.name.indexOf('Y') === -1) newY = 0;
			if (this._selected.name.indexOf('Z') === -1) newZ = 0;

			let temp = [
				nowVec3x[0] * newX + nowVec3y[0] * newY + nowVec3z[0] * newZ,
				nowVec3x[1] * newX + nowVec3y[1] * newY + nowVec3z[1] * newZ,
				nowVec3x[2] * newX + nowVec3y[2] * newY + nowVec3z[2] * newZ
			];
			let beforeSnap = MathUtils.addVector(this._objectPoint, temp);

			this.object.position = [
				this._snap > 0 ? (beforeSnap[0] - (beforeSnap[0] % this._snap)) : beforeSnap[0],
				this._snap > 0 ? (beforeSnap[1] - (beforeSnap[1] % this._snap)) : beforeSnap[1],
				this._snap > 0 ? (beforeSnap[2] - (beforeSnap[2] % this._snap)) : beforeSnap[2]
			];
		}
		else {
			this.object.position = this._newVariety;
		}
		this._updateRealObjectsTransform();
	}

	_turnAngle() {
		if ((this._statsData[0] + this._statsData[1] + this._statsData[2]) === 1) {
			if (this._space === 'local') {
				let axis = MathUtils.vec3ApplyQuat(this._statsData, this._objQuaterStart);
				this._jd = this._calculateAngle(axis);
				this._objCurrentQuaterEng = MathUtils.getQuatFromAxisAngle(axis, this._jd);
				this.object.localQuaternion = MathUtils.multiplyQuat(MathUtils.normalizeQuat(this._objCurrentQuaterEng), this._objQuaterStart);
			}
			else {
				this._jd = this._calculateAngle(this._statsData);
				this._objCurrentQuaterEng = MathUtils.getQuatFromAxisAngle(this._statsData, this._jd);
				this.object.quaternion = MathUtils.multiplyQuat(this._objCurrentQuaterEng, this._objQuaterStart);
			}
		}
		else {
			let cameraNor = MathUtils.normalizeVector(MathUtils.subVector(this.object.app.camera.position, this.app.camera.target));
			this._jd = this._calculateAngle(cameraNor);
			this._objCurrentQuaterEng = MathUtils.getQuatFromAxisAngle(cameraNor, this._jd)
			this.object.quaternion = MathUtils.multiplyQuat(this._objCurrentQuaterEng, this._objQuaterStart);
		}
		this._updateRealObjectsTransform();
	}

	_turnScale() {
		let scale = [1, 1, 1];
		if (this._selected.name === "ScaleXYZ") {
			let startLength = MathUtils.getDistance(this._startPoint, [0, 0, 0]);
			let nowLength = MathUtils.getDistance(this._intersection, [0, 0, 0]);
			let bili = nowLength / startLength;
			if (MathUtils.dotVector(this._intersection, this._startPoint) < 0) {
				bili *= -1;
			}
			scale = [
				this._snap > 0 ? (this._scaleData[0] * bili - (this._scaleData[0] * bili % this._snap)) : this._scaleData[0] * bili,
				this._snap > 0 ? (this._scaleData[1] * bili - (this._scaleData[1] * bili % this._snap)) : this._scaleData[1] * bili,
				this._snap > 0 ? (this._scaleData[2] * bili - (this._scaleData[2] * bili % this._snap)) : this._scaleData[2] * bili
			];
		}
		else {
			let _tempVector = MathUtils.vec3ApplyQuat(this._startPoint, this._invert(this.object.quaternion));
			let _tempVector2 = MathUtils.vec3ApplyQuat(this._intersection, this._invert(this.object.quaternion));
			let temp = [
				_tempVector2[0] / _tempVector[0],
				_tempVector2[1] / _tempVector[1],
				_tempVector2[2] / _tempVector[2]
			];
			if (this._selected.name.indexOf('X') === -1) temp[0] = 1;
			if (this._selected.name.indexOf('Y') === -1) temp[1] = 1;
			if (this._selected.name.indexOf('Z') === -1) temp[2] = 1;

			scale = [
				this._scaleData[0] * temp[0],
				this._scaleData[1] * temp[1],
				this._scaleData[2] * temp[2]
			];
		}

		if (scale[0] === 0) {
			scale[0] = 0.001;
		}
		if (scale[1] === 0) {
			scale[1] = 0.001;
		}
		if (scale[2] === 0) {
			scale[2] = 0.001;
		}

		this.object.scale = scale;

		this._updateRealObjectsTransform();
	}

	_calculateAngle(axis) {
		let ON = MathUtils.getDistance(this._intersection, [0, 0, 0]);
		let OL = MathUtils.getDistance(this._startPoint, [0, 0, 0]);
		let NL = MathUtils.getDistance(this._startPoint, this._intersection);
		let cosNL = (OL * OL + ON * ON - NL * NL) / (2 * OL * ON);
		let angle = MathUtils.radToDeg(MathUtils.acos(cosNL));
		let from = MathUtils.normalizeVector(this._startPoint);
		let to = MathUtils.normalizeVector(this._intersection);
		let v3 = MathUtils.crossVector(from, to);

		let beforeSnap = this._cosData(v3, axis) > 0 ? angle : 360 - angle;
		return this._snap > 0 ? (beforeSnap - beforeSnap % this._snap) : beforeSnap;
	}

	_invert(q) {
		let temp = [];
		temp[0] = q[0] * -1;
		temp[1] = q[1] * -1;
		temp[2] = q[2] * -1;
		temp[3] = q[3];

		return temp;
	}

	_cosData(a, b) {
		return MathUtils.dotVector(a, b) / (MathUtils.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]) * MathUtils.sqrt(b[0] * b[0] + b[1] * b[1] + b[2] * b[2]));
	}

	_createAxisLine(position, angle4, scale, color, depthTest, name) {
		let points = [];
		let target = MathUtils.addVector([0, 0, 0], MathUtils.scaleVector([1, 0, 0], 1.85));
		points.push([0, 0, 0]);
		points.push(target);

		let axisLine = new FatLine({
			selfPoints: points,
			width: 3
		});

		this._objAttribute(axisLine, position, angle4, scale, color, depthTest, name);
	}

	_createAxisPlane(position, angle4, scale, color, depthTest, name) {
		var ZeroPos = [0, 0, 0];
		var PosX = [0.4, 0, 0];
		var PosZ = [0, 0, 0.4];

		var points = [ZeroPos, PosX, MathUtils.addVector(PosX, PosZ), PosZ];
		var axisPlane = new PlaneRegion({ points: points });

		this._objAttribute(axisPlane, position, angle4, scale, color, depthTest, name);
	}

	_createAxisCenter(position, angle4, scale, color, depthTest, name) {
		let axisXYZCenter = new Sphere(0.15);

		this._objAttribute(axisXYZCenter, position, angle4, scale, color, depthTest, name);
	}

	_createAxisCone(position, angle4, scale, color, depthTest, name) {
		let shape = {};
		shape.data = MeshBuilder.createCylinder({ radiusTop: 0, radiusBottom: 0.1, height: 0.3 })
		let cone = new Mesh(shape);

		this._objAttribute(cone, position, angle4, scale, color, depthTest, name);
	}

	_createAxisCircle(position, angle4, scale, color, depthTest, name, arcs) {
		let circleHelper = {};
		circleHelper.data = MeshBuilder.createTorus({ radius: 1.4, tube: 0.04, arc: arcs * Math.PI * 2 })
		let AxisCircle = new Mesh(circleHelper);
		this._objAttribute(AxisCircle, position, angle4, scale, color, depthTest, name);
	}

	_createScaleBox(position, angle4, scale, color, depthTest, name) {
		let axisBox = new Box(0.3, 0.3, 0.3);
		this._objAttribute(axisBox, position, angle4, scale, color, depthTest, name);
	}

	_objAttribute(obj, position, angle4, scale, color, depthTest, name) {
		obj.castShadow = false;
		obj.receiveShadow = false;
		obj.style.lights = true;
		obj.style.color = color;
		obj.style.opacity = 0.99;
		obj.style.depthTest = depthTest;
		obj.renderOrder = 100000;
		obj.name = name;
		if (this._helperParentObj) { obj.parent = this._helperParentObj; }
		obj.position = position;

		if (obj.name === 'AxisXY' || obj.name === 'AxisYZ' || obj.name === 'AxisXZ') {
			obj.style.sideType = 'Double';
		}

		if (obj.name === 'anglesXYZ' || obj.name === 'anglesXYZE') { obj.lookAt(this.object.app.camera, { always: true }); }
		obj.scale = scale;
		obj.quaternion = [angle4[0], angle4[1], angle4[2], angle4[3]];

		if (obj.name === 'anglesX') {
			this._objAngleQuaternionX = [
				obj.quaternion[0],
				obj.quaternion[1],
				obj.quaternion[2],
				obj.quaternion[3]
			];
		}
		if (obj.name === 'anglesY') {
			this._objAngleQuaternionY = [
				obj.quaternion[0],
				obj.quaternion[1],
				obj.quaternion[2],
				obj.quaternion[3]
			];
		}
		if (obj.name === 'anglesZ') {
			this._objAngleQuaternionZ = [
				obj.quaternion[0],
				obj.quaternion[1],
				obj.quaternion[2],
				obj.quaternion[3]
			];
		}

		if (obj.name === 'anglesXYZE') { return; }
		this._objHelpers.push(obj);
	}

	_destroys() {
		if (this._objHelpers.length !== 0) {
			for (let val of this._objHelpers) {
				if (val) {
					if (val.name === 'anglesXYZ' || val.name === 'anglesXYZE') { val.lookAt(); }
					val.destroy();
				}
			}
			this._objHelpers = [];
			this._helperParentObj.destroy();
			this._helperParentObj = null;
		}
	}

	/**
	 * 控制变换模式,包括平移translate、旋转angle和缩放scale,默认为平移。
	 * @type {string}
	 * @public
	 */
	set mode(mode) {
		this._mode = mode;

		if (mode === 'angle') {
			this._mode = 'rotate';
		}

		// 总是重新创建helper,确保轴锁定功能正常工作
		if (this._helperParentObj) {
			this._createHelperAxis();
		}
	}
	get mode() {
		return this._mode;
	}

	/**
	 * 控制坐标系的变换,包括世界坐标系world和本地坐标系local,默认为世界坐标系。
	 * @type {string}
	 * @public
	 */
	set space(space) {
		this._space = space;
		// 总是重新创建helper,确保轴锁定功能正常工作
		if (this._helperParentObj) {
			this._createHelperAxis();
		}
	}
	get space() {
		return this._space;
	}

	/**
	 * 设置物体操作时平移、旋转和缩放变化的阈值。
	 * @type {number}
	 * @public
	 */
	set snap(snap) {
		this._snap = snap;
		if (this._snap < 0) {
			this._snap = 0;
		}
	}
	get snap() {
		return this._snap;
	}

	/**
	 * 设置操作杆是否固定呈现出的大小,true开启、false关闭,默认开启。
	 * @type {boolean}
	 * @public
	 */
	set keepSize(bool) {
		this._keepSize = bool;
	}
	get keepSize() {
		return this._keepSize;
	}

	/**
	 * 操作杆固定大小情况下,再设置操作杆的大小。
	 * @type {number}
	 * @public
	 */
	set size(size) {
		this._size = size;
	}
	get size() {
		return this._size;
	}

	/**
	 * 设置多个需添加组件的对象。
	 * @param {Array.<Object>} objs - 需要添加组件的对象。
	 * @param {boolean} ignoreCenter - 是否忽略中心位置,默认为false,表示不忽略中心位置,需计算中心点。
	 * @public
	 */
	setObjects(objs = [], ignoreCenter = false) {
		if (!objs.length) {
			if (this._helperParentObj) {
				this._helperParentObj.active = false;
			}
			return;
		}
		let axisPosition = [0, 0, 0];
		if (!ignoreCenter) {
			let max = [...objs[0].position], min = [...objs[0].position];
			for (let i = 1; i < objs.length; i++) {
				const objPosition = objs[i].position;
				max[0] = MathUtils.max(objPosition[0], max[0]);
				max[1] = MathUtils.max(objPosition[1], max[1]);
				max[2] = MathUtils.max(objPosition[2], max[2]);

				min[0] = MathUtils.min(objPosition[0], min[0]);
				min[1] = MathUtils.min(objPosition[1], min[1]);
				min[2] = MathUtils.min(objPosition[2], min[2]);
			}
			axisPosition = MathUtils.addVector(min, MathUtils.divideVector(MathUtils.subVector(max, min), 2));
		}

		this.object.position = axisPosition;
		
		// 确保helper被创建并激活
		if (!this._helperParentObj) {
			this._createHelperAxis();
		}
		this._helperParentObj.active = true;

		this._createObjMap(objs);
	}

	/**
	 * 获取添加组件的对象。
	 * @returns {Array.<Object>} 添加组件的对象。
	 * @public
	 */
	getObjects() {
		return Object.values(this._objMap);
	}

	_createObjMap(objs) {
		// 清空数组和map
		if (this._emptyObjects.length) {
			for (let i = 0; i < this._emptyObjects.length; i++) {
				const emptyObject = this._emptyObjects[i];
				emptyObject.destroy();
			}
			this._emptyObjects = [];
		}
		this._objMap = {};

		if (objs.length === 1) {
			this.object.matrixWorld = objs[0].matrixWorld;
		}

		// 重新设置父子集,数据和map
		for (let i = 0; i < objs.length; i++) {
			const obj = objs[i];
			this._objMap[obj.uuid] = obj;
			const emptyObject = new Object3D();
			// 设置为空对象的子,操作杆操作的实际为空对象,再把空对象的matrix更新给真正的对象,避免更改场景树的结构
			emptyObject.parent = this.object;
			// 方便后续通过name字段拿map里的value
			emptyObject.name = obj.uuid;
			// 继承原先对象的matrix,方便后续直接赋值
			emptyObject.matrixWorld = obj.matrixWorld;
			this._emptyObjects.push(emptyObject);
		}
	}

	_updateRealObjectsTransform() {
		for (let i = 0; i < this._emptyObjects.length; i++) {
			const emptyObject = this._emptyObjects[i];
			const realObject = this._objMap[emptyObject.name];
			realObject.matrixWorld = emptyObject.matrixWorld;
		}

		this.object.trigger('TRANSFORM_CONTROL_UPDATE');
	}

	/**
	 * 锁定指定轴,使其无法移动
	 * @param {string} axis - 要锁定的轴 ('x', 'y', 'z', 'xy', 'yz', 'xz', 'xyz')
	 * @param {boolean} locked - 是否锁定
	 * @public
	 */
	lockAxis(axis, locked = true) {
		let needUpdate = false;
		
		if (axis === 'x' || axis === 'X') {
			if (this._lockedAxes.x !== locked) {
				this._lockedAxes.x = locked;
				needUpdate = true;
			}
		} else if (axis === 'y' || axis === 'Y') {
			if (this._lockedAxes.y !== locked) {
				this._lockedAxes.y = locked;
				needUpdate = true;
			}
		} else if (axis === 'z' || axis === 'Z') {
			if (this._lockedAxes.z !== locked) {
				this._lockedAxes.z = locked;
				needUpdate = true;
			}
		} else if (axis === 'xy' || axis === 'XY') {
			if (this._lockedAxes.x !== locked || this._lockedAxes.y !== locked) {
				this._lockedAxes.x = locked;
				this._lockedAxes.y = locked;
				needUpdate = true;
			}
		} else if (axis === 'yz' || axis === 'YZ') {
			if (this._lockedAxes.y !== locked || this._lockedAxes.z !== locked) {
				this._lockedAxes.y = locked;
				this._lockedAxes.z = locked;
				needUpdate = true;
			}
		} else if (axis === 'xz' || axis === 'XZ') {
			if (this._lockedAxes.x !== locked || this._lockedAxes.z !== locked) {
				this._lockedAxes.x = locked;
				this._lockedAxes.z = locked;
				needUpdate = true;
			}
		} else if (axis === 'xyz' || axis === 'XYZ') {
			if (this._lockedAxes.x !== locked || this._lockedAxes.y !== locked || this._lockedAxes.z !== locked) {
				this._lockedAxes.x = locked;
				this._lockedAxes.y = locked;
				this._lockedAxes.z = locked;
				needUpdate = true;
			}
		}
		
		// 如果轴锁定状态发生变化,重新创建helper
		if (needUpdate && this._helperParentObj) {
			this._createHelperAxis();
			// 确保helper的激活状态正确
			if (this._helperParentObj) {
				this._helperParentObj.active = !!this._objMap && Object.keys(this._objMap).length > 0;
			}
		}
	}

	/**
	 * 锁定所有轴
	 * @public
	 */
	lockAllAxes() {
		this.lockAxis('xyz', true);
	}

	/**
	 * 解锁所有轴
	 * @public
	 */
	unlockAllAxes() {
		this.lockAxis('xyz', false);
	}

	/**
	 * 解锁指定轴
	 * @param {string} axis - 要解锁的轴 ('x', 'y', 'z', 'xy', 'yz', 'xz', 'xyz')
	 * @public
	 */
	unlockAxis(axis) {
		this.lockAxis(axis, false);
	}

	/**
	 * 获取轴的锁定状态
	 * @param {string} axis - 轴名称 ('x', 'y', 'z')
	 * @returns {boolean} 是否锁定
	 * @public
	 */
	isAxisLocked(axis) {
		if (axis === 'x' || axis === 'X') {
			return this._lockedAxes.x;
		} else if (axis === 'y' || axis === 'Y') {
			return this._lockedAxes.y;
		} else if (axis === 'z' || axis === 'Z') {
			return this._lockedAxes.z;
		}
		return false;
	}

	
	/**
	 * 获取当前轴锁定状态
	 * @returns {object} 轴锁定状态
	 * @public
	 */
	getLockedAxesState() {
		return { ...this._lockedAxes };
	}


}

export { TransformControlComponent }