import {FloatUtil} from '../common/lang/FloatUtil'; import {Vector3} from './Vector3'; //========================================================== // 四元数。 // // @struct // @author maocy // @version 150109 //========================================================== export class Quaternion2 { // @attribute public x: number; public y: number; public z: number; public w: number; //============================================================ // 构造处理。 // // @method // @param l:width:Number 宽度 // @param t:height:Number 高度 // @param r:deep:Number 深度 // @param b:deep:Number 深度 //============================================================ constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 1) { this.x = x; this.y = y; this.z = z; this.w = w; } //============================================================ // 单位化处理。 // // @method //============================================================ public identity() { this.x = this.y = this.z = 0; this.w = 1; return this; } //============================================================ // 接收一个四元数。 // // @method // @param value:SQuaternion 四元数 //============================================================ public assign(value) { this.x = value.x; this.y = value.y; this.z = value.z; this.w = value.w; } //============================================================ // 设置数据内容。 // // @method // @param x:Number X分量 // @param y:Number Y分量 // @param z:Number Z分量 // @param w:Number W分量 //============================================================ public set(x, y, z, w) { this.x = x; this.y = y; this.z = z; this.w = w; } //============================================================ // 获得绝对值。 // // @method // @return Number 绝对值 //============================================================ public absolute() { return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z) + (this.w * this.w)); } //============================================================ // 单位化处理。 // // @method //============================================================ public normalize() { var value = this.absolute(); if (value != 0) { var rate = 1 / value; this.x *= rate; this.y *= rate; this.z *= rate; this.w *= rate; } } //============================================================ // 获得反方向。 // // @method // @param value:SQuaternion 四元数 // @return SQuaternion 四元数 //============================================================ public conjugate(value: Quaternion2 = null) { var result = null; if (value) { result = value; } else { result = new Quaternion2(); } result.x = -this.x; result.y = -this.y; result.z = -this.z; result.w = this.w; return result; } //============================================================ // 乘法处理。 // // @method // @param value:SQuaternion 四元数 //============================================================ public mul(value) { var x = this.x; var y = this.y; var z = this.z; var w = this.w; this.x = (w * value.x) + (x * value.w) + (y * value.z) - (z * value.y); this.y = (w * value.y) + (y * value.w) + (z * value.x) - (x * value.z); this.z = (w * value.z) + (z * value.w) + (x * value.y) - (y * value.x); this.w = (w * value.w) - (x * value.x) - (y * value.y) - (z * value.z); } //============================================================ // 乘法处理。 // // @method // @param value1:SQuaternion 四元数1 // @param value2:SQuaternion 四元数2 //============================================================ public mul2(value1, value2) { this.x = (value1.w * value2.x) + (value1.x * value2.w) + (value1.y * value2.z) - (value1.z * value2.y); this.y = (value1.w * value2.y) + (value1.y * value2.w) + (value1.z * value2.x) - (value1.x * value2.z); this.z = (value1.w * value2.z) + (value1.z * value2.w) + (value1.x * value2.y) - (value1.y * value2.x); this.w = (value1.w * value2.w) - (value1.x * value2.x) - (value1.y * value2.y) - (value1.z * value2.z); } //============================================================ // 变换三维矢量。 // // @method // @param input:SVector3 输入方向 // @param output:SVector3 输出方向 //============================================================ public translate(input, output) { // 计算内容 var q1 = new Quaternion2(); q1.set(input.x, input.y, input.z, 0); q1.normalize(); var q2 = this.conjugate(); q1.mul(q2); var q = this.clone(); q.mul(q1); // 返回结果 var result = null; if (output) { result = output; } else { result = new Vector3(); } result.set(q.x, q.y, q.z); return result; } //============================================================ // 计算插值。 // // @method // @param value1:SQuaternion 开始四元数 // @param value2:SQuaternion 结束四元数 // @param rate:Float 比率 //============================================================ public slerp(value1, value2, rate) { var rv = (value1.x * value2.x) + (value1.y * value2.y) + (value1.z * value2.z) + (value1.w * value2.w); var rf = false; if (rv < 0) { rf = true; rv = -rv; } var r1 = 0; var r2 = 0; if (rv > 0.999999) { r1 = 1 - rate; r2 = rf ? -rate : rate; } else { var ra = Math.acos(rv); var rb = 1 / Math.sin(ra); r1 = Math.sin((1 - rate) * ra) * rb; r2 = rf ? (-Math.sin(rate * ra) * rb) : (Math.sin(rate * ra) * rb); } this.x = (r1 * value1.x) + (r2 * value2.x); this.y = (r1 * value1.y) + (r2 * value2.y); this.z = (r1 * value1.z) + (r2 * value2.z); this.w = (r1 * value1.w) + (r2 * value2.w); } //========================================================== // 用轴向量和旋转角创建一个四元组。 // // @method // @param axis:SVector3 方向轴 // @param angle:Number 弧度 //========================================================== public fromAxisAngle(axis, angle) { var r = angle * 0.5; var s = Math.sin(r); this.x = axis.x * s; this.y = axis.y * s; this.z = axis.z * s; this.w = Math.cos(r); } //========================================================== // 从欧拉角获得四元数。 // // @method // @param p:pitch:Number X转角 // @param y:yaw:Number Y转角 // @param r:roll:Number Z转角 //========================================================== public fromEuler(p, y, r) { var sr = Math.sin(r * 0.5); var cr = Math.cos(r * 0.5); var sp = Math.sin(p * 0.5); var cp = Math.cos(p * 0.5); var sy = Math.sin(y * 0.5); var cy = Math.cos(y * 0.5); this.x = cr * sp * cy + sr * cp * sy; this.y = cr * cp * sy - sr * sp * cy; this.z = sr * cp * cy - cr * sp * sy; this.w = cr * cp * cy + sr * sp * sy; } //========================================================== // 从四元数获得欧拉角。 // // @method // @param p:pitch:Number X转角 // @param y:yaw:Number Y转角 // @param r:roll:Number Z转角 //========================================================== public parseEuler(p) { var x2 = this.x * this.x; var y2 = this.y * this.y; var z2 = this.z * this.z; // 输出内容 var r = null; if (p) { r = p; } else { r = new Vector3(); } r.x = Math.asin(FloatUtil.toRange((this.w * this.x - this.y * this.z) * 2, -1, 1)); r.y = Math.atan2(2 * (this.w * this.y + this.z * this.x), 1 - 2 * (x2 + y2)); r.z = Math.atan2(2 * (this.w * this.z + this.x * this.y), 1 - 2 * (z2 + x2)); return r; } //========================================================== // 序列化数据到输出流里。 // // @param output 数据流 //========================================================== public serialize(output) { output.writeFloat(this.x); output.writeFloat(this.y); output.writeFloat(this.z); output.writeFloat(this.w); } //========================================================== // 从输入流里反序列化数据。 // // @param input 数据流 //========================================================== public unserialize(input) { this.x = input.readFloat(); this.y = input.readFloat(); this.z = input.readFloat(); this.w = input.readFloat(); } //============================================================ // 获得克隆对象。 // // @method // @return SQuaternion 克隆对象 //============================================================ public clone() { var result = new Quaternion2(); result.x = this.x; result.y = this.y; result.z = this.z; result.w = this.w; return result; } //============================================================ // 获得字符串。 // // @method // @return String 字符串 //============================================================ public toString() { return this.x + ',' + this.y + ',' + this.z + ',' + this.w; } }