axmol/cocos/math/Mat3.cpp

1006 lines
22 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Mat3.h"
NS_CC_MATH_BEGIN
/**
* Constructor instantiates a new Mat3 object. The initial
* values for the matrix is that of the identity matrix.
* 默认构造单位矩阵
*
*/
Mat3::Mat3() {
loadIdentity();
}
/**
* constructs a matrix with the given values.
*
* @param m[0]
* 0x0 in the matrix.
* @param m[1]
* 0x1 in the matrix.
* @param m[2]
* 0x2 in the matrix.
* @param m[3]
* 1x0 in the matrix.
* @param m[4]
* 1x1 in the matrix.
* @param m[5]
* 1x2 in the matrix.
* @param m[6]
* 2x0 in the matrix.
* @param m[7]
* 2x1 in the matrix.
* @param m[8]
* 2x2 in the matrix.
*/
Mat3::Mat3(float m[9]) {
this->m[0] = m[0];
this->m[1] = m[1];
this->m[2] = m[2];
this->m[3] = m[3];
this->m[4] = m[4];
this->m[5] = m[5];
this->m[6] = m[6];
this->m[8] = m[7];
this->m[9] = m[8];
}
/**
* get retrieves a value from the matrix at the given position.
* If the position is invalid a JmeException is thrown.
* 获取指定位置的元素值
*
* @param i
* the row index.行索引取值范围0、1、2
* @param j
* the colum index.列索引取值范围0、1、2
* @return the value at (i, j).
*/
float Mat3::get(int i, int j) {
switch (i) {
case 0:
switch (j) {
case 0:
return m[0];
case 1:
return m[1];
case 2:
return m[2];
}
case 1:
switch (j) {
case 0:
return m[3];
case 1:
return m[4];
case 2:
return m[5];
}
case 2:
switch (j) {
case 0:
return m[6];
case 1:
return m[7];
case 2:
return m[8];
}
}
return 0.0f;
// throw new JmeException("Invalid indices into matrix.");
}
/**
* getColumn returns one of three columns specified by the
* parameter. This column is returned as a cocos2d::Vec3 object.
* 获取指定列构造的向量
*
* @param i
* the column to retrieve. Must be between 0 and 2.
* @param store
* the vector object to store the result in. if null, a new one
* is created.
* @return the column specified by the index.
*/
cocos2d::Vec3 Mat3::getColumn(int i) {
cocos2d::Vec3 store;
switch (i) {
case 0:
store.x = m[0];
store.y = m[3];
store.z = m[6];
break;
case 1:
store.x = m[1];
store.y = m[4];
store.z = m[7];
break;
case 2:
store.x = m[2];
store.y = m[5];
store.z = m[8];
break;
default:;
//logger.warning("Invalid column index.");
//throw new JmeException("Invalid column index. " + i);
}
return store;
}
/**
* getRow returns one of three rows as specified by the
* parameter. This row is returned as a cocos2d::Vec3 object.
* 获取指定行构造的向量
*
* @param i
* the row to retrieve. Must be between 0 and 2.
* @param store
* the vector object to store the result in. if null, a new one
* is created.
* @return the row specified by the index.
*/
cocos2d::Vec3 Mat3::getRow(int i) {
cocos2d::Vec3 store;
switch (i) {
case 0:
store.x = m[0];
store.y = m[1];
store.z = m[2];
break;
case 1:
store.x = m[3];
store.y = m[4];
store.z = m[5];
break;
case 2:
store.x = m[6];
store.y = m[7];
store.z = m[8];
break;
default:;
// throw new JmeException("Invalid row index. " + i);
}
return store;
}
std::string Mat3::toString() {
return "";
}
/**
*
* setColumn sets a particular column of this matrix to that
* represented by the provided vector.
* 根据给定列向量设置矩阵的列
*
* @param i
* the column to set.
* @param column
* the data to set.
*/
void Mat3::setColumn(int i, const cocos2d::Vec3& column) {
switch (i) {
case 0:
m[0] = column.x;
m[3] = column.y;
m[6] = column.z;
break;
case 1:
m[1] = column.x;
m[4] = column.y;
m[7] = column.z;
break;
case 2:
m[2] = column.x;
m[5] = column.y;
m[8] = column.z;
break;
default:;
//logger.warning("Invalid column index.");
//throw new JmeException("Invalid column index. " + i);
}
}
/**
*
* setRow sets a particular row of this matrix to that
* represented by the provided vector.
* 根据给定行向量设置矩阵的行
*
* @param i
* the row to set.
* @param row
* the data to set.
*/
void Mat3::setRow(int i, const cocos2d::Vec3& row) {
switch (i) {
case 0:
m[0] = row.x;
m[1] = row.y;
m[2] = row.z;
break;
case 1:
m[3] = row.x;
m[4] = row.y;
m[5] = row.z;
break;
case 2:
m[6] = row.x;
m[7] = row.y;
m[8] = row.z;
break;
default:;
// logger.warning("Invalid row index.");
// throw new JmeException("Invalid row index. " + i);
}
}
/**
* set places a given value into the matrix at the given
* position. If the position is invalid a JmeException is
* thrown.
* 设定某位置的值
*
* @param i
* the row index.
* @param j
* the colum index.
* @param value
* the value for (i, j).
*/
void Mat3::set(int i, int j, float value) {
switch (i) {
case 0:
switch (j) {
case 0:
m[0] = value;
return;
case 1:
m[1] = value;
return;
case 2:
m[2] = value;
return;
}
case 1:
switch (j) {
case 0:
m[3] = value;
return;
case 1:
m[4] = value;
return;
case 2:
m[5] = value;
return;
}
case 2:
switch (j) {
case 0:
m[6] = value;
return;
case 1:
m[7] = value;
return;
case 2:
m[8] = value;
return;
}
}
//logger.warning("Invalid matrix index.");
//throw new JmeException("Invalid indices into matrix.");
}
/**
*
* set sets the values of the matrix to those supplied by the
* 3x3 two dimenion array.
* 用二维数组设置矩阵各元素值
*
* @param matrix
* the new values of the matrix.
* @throws JmeException
* if the array is not of size 9.
*/
void Mat3::set(float matrix[3][3]) {
//if (matrix.length != 3 || matrix[0].length != 3) {
// throw new JmeException("Array must be of size 9.");
//}
m[0] = matrix[0][0];
m[1] = matrix[0][1];
m[2] = matrix[0][2];
m[3] = matrix[1][0];
m[4] = matrix[1][1];
m[5] = matrix[1][2];
m[6] = matrix[2][0];
m[7] = matrix[2][1];
m[8] = matrix[2][2];
}
/**
* Recreate Matrix using the provided axis.
* 根据给定各列向量构造矩阵
*
* @param uAxis
* cocos2d::Vec3
* @param vAxis
* cocos2d::Vec3
* @param wAxis
* cocos2d::Vec3
*/
void Mat3::set(const cocos2d::Vec3& uAxis, const cocos2d::Vec3& vAxis, const cocos2d::Vec3& wAxis) {
m[0] = uAxis.x;
m[3] = uAxis.y;
m[6] = uAxis.z;
m[1] = vAxis.x;
m[4] = vAxis.y;
m[7] = vAxis.z;
m[2] = wAxis.x;
m[5] = wAxis.y;
m[8] = wAxis.z;
}
/**
* set sets the values of this matrix from an array of values;
* 根据给定数组按行或列设置矩阵
*
* @param matrix
* the matrix to set the value to.
* @param rowMajor
* whether the incoming data is in row or column major order.
*/
void Mat3::set(float matrix[9], bool rowMajor) {
//if (matrix.length != 9)
// throw new JmeException("Array must be of size 9.");
if (rowMajor) {
m[0] = matrix[0];
m[1] = matrix[1];
m[2] = matrix[2];
m[3] = matrix[3];
m[4] = matrix[4];
m[5] = matrix[5];
m[6] = matrix[6];
m[7] = matrix[7];
m[8] = matrix[8];
}
else {
m[0] = matrix[0];
m[1] = matrix[3];
m[2] = matrix[6];
m[3] = matrix[1];
m[4] = matrix[4];
m[5] = matrix[7];
m[6] = matrix[2];
m[7] = matrix[5];
m[8] = matrix[8];
}
}
/**
* fromAngleNormalAxis sets this matrix4f to the values
* specified by an angle and a normalized axis of rotation.
* 绕轴axis单位向量旋转angle弧度角的3D旋转矩阵
*
* @param angle
* the angle to rotate (in radians).
* @param axis
* the axis of rotation (already normalized).
*/
/**
* Creates a matrix describing a rotation around the z-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
/**
* Creates a matrix describing a rotation around the y-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
/**
* Creates a matrix describing a rotation around the x-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
/**
* Creates a matrix describing a rotation around the z-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
/**
* Creates a matrix describing a rotation around the y-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
/**
* Creates a matrix describing a rotation around the x-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
/**
* 是否单位矩阵
*
* @return true if this matrix is identity
*/
/**
* loadIdentity sets this matrix to the identity matrix. Where
* all values are zero except those along the diagonal which are one.
* 单位矩阵
*
*/
void Mat3::loadIdentity() {
m[1] = m[2] = m[3] = m[5] = m[6] = m[7] = 0;
m[0] = m[4] = m[8] = 1;
}
bool Mat3::isIdentity() {
return (m[0] == 1 && m[1] == 0 && m[2] == 0)
&& (m[3] == 0 && m[4] == 1 && m[5] == 0)
&& (m[6] == 0 && m[7] == 0 && m[8] == 1);
}
void Mat3::rotateX(float angle)
{
rotateX(std::sin(angle), std::cos(angle));
}
void Mat3::rotateY(float angle)
{
rotateY(std::sin(angle), std::cos(angle));
}
void Mat3::rotateZ(float angle)
{
rotateZ(std::sin(angle), std::cos(angle));
}
void Mat3::rotateX(float s, float c)
{
Mat3 temp;
temp.createRotationX(s, c);
mult(temp);
}
void Mat3::rotateY(float s, float c)
{
Mat3 temp;
temp.createRotationY(s, c);
mult(temp);
}
void Mat3::rotateZ(float s, float c)
{
Mat3 temp;
temp.createRotationZ(s, c);
mult(temp);
}
void Mat3::createRotation(const cocos2d::Vec3& axis, float fSin, float fCos) {
float x = axis.x;
float y = axis.y;
float z = axis.z;
// Make sure the input axis is normalized.
float n = x * x + y * y + z * z;
if (n != 1.0f)
{
// Not normalized.
n = sqrt(n);
// Prevent divide too close to zero.
if (n > 0.000001f)
{
n = 1.0f / n;
x *= n;
y *= n;
z *= n;
}
}
float fOneMinusCos = ((float)1.0) - fCos;
float fX2 = x * x;
float fY2 = y * y;
float fZ2 = z * z;
float fXYM = x * y * fOneMinusCos;
float fXZM = x * z * fOneMinusCos;
float fYZM = y * z * fOneMinusCos;
float fXSin = x * fSin;
float fYSin = y * fSin;
float fZSin = z * fSin;
m[0] = fX2 * fOneMinusCos + fCos;
m[1] = fXYM - fZSin;
m[2] = fXZM + fYSin;
m[3] = fXYM + fZSin;
m[4] = fY2 * fOneMinusCos + fCos;
m[5] = fYZM - fXSin;
m[6] = fXZM - fYSin;
m[7] = fYZM + fXSin;
m[8] = fZ2 * fOneMinusCos + fCos;
}
/**
* Creates a matrix describing a rotation around the x-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
void Mat3::createRotationX(float s, float c)
{
m[4] = c;
m[5] = s;
m[7] = -s;
m[8] = c;
}
/**
* Creates a matrix describing a rotation around the y-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
void Mat3::createRotationY(float s, float c)
{
m[0] = c;
m[2] = -s;
m[6] = s;
m[8] = c;
}
/**
* Creates a matrix describing a rotation around the z-axis.
*
* @param angle The angle of rotation (in radians).
* @param dst A matrix to store the result in.
*/
void Mat3::createRotationZ(float s, float c)
{
m[0] = c;
m[1] = s;
m[3] = -s;
m[4] = c;
}
Mat3& Mat3::mult(const Mat3& mat, Mat3& product) const
{
float temp00, temp01, temp02;
float temp10, temp11, temp12;
float temp20, temp21, temp22;
temp00 = m[0] * mat.m[0] + m[1] * mat.m[3] + m[2] * mat.m[6];
temp01 = m[0] * mat.m[1] + m[1] * mat.m[4] + m[2] * mat.m[7];
temp02 = m[0] * mat.m[2] + m[1] * mat.m[5] + m[2] * mat.m[8];
temp10 = m[3] * mat.m[0] + m[4] * mat.m[3] + m[5] * mat.m[6];
temp11 = m[3] * mat.m[1] + m[4] * mat.m[4] + m[5] * mat.m[7];
temp12 = m[3] * mat.m[2] + m[4] * mat.m[5] + m[5] * mat.m[8];
temp20 = m[6] * mat.m[0] + m[7] * mat.m[3] + m[8] * mat.m[6];
temp21 = m[6] * mat.m[1] + m[7] * mat.m[4] + m[8] * mat.m[7];
temp22 = m[6] * mat.m[2] + m[7] * mat.m[5] + m[8] * mat.m[8];
product.m[0] = temp00;
product.m[1] = temp01;
product.m[2] = temp02;
product.m[3] = temp10;
product.m[4] = temp11;
product.m[5] = temp12;
product.m[6] = temp20;
product.m[7] = temp21;
product.m[8] = temp22;
return product;
}
/**
* Multiplies this 3x3 matrix by the 1x3 Vector vec and stores the result in
* product.
* 矩阵乘以向量结果存入参数product中
*
* @param vec
* The cocos2d::Vec3 to multiply.
* @return The given product vector.
*/
cocos2d::Vec3 Mat3::mult(const cocos2d::Vec3& vec) const {
cocos2d::Vec3 product;
float x = vec.x;
float y = vec.y;
float z = vec.z;
product.x = m[0] * x + m[1] * y + m[2] * z;
product.y = m[3] * x + m[4] * y + m[5] * z;
product.z = m[6] * x + m[7] * y + m[8] * z;
return product;
}
/**
* multLocal multiplies this matrix internally by a given float
* scale factor.
* 矩阵标量乘
*
* @param scale
* the value to scale by.
* @return this Mat3
*/
Mat3& Mat3::multLocal(float scale) {
m[0] *= scale;
m[1] *= scale;
m[2] *= scale;
m[3] *= scale;
m[4] *= scale;
m[5] *= scale;
m[6] *= scale;
m[7] *= scale;
m[8] *= scale;
return *this;
}
/**
* add adds the values of a parameter matrix to this matrix.
* 矩阵加法
*
* @param mat
* the matrix to add to this.
*/
Mat3& Mat3::addLocal(const Mat3& mat) {
m[0] += mat.m[0];
m[1] += mat.m[1];
m[2] += mat.m[2];
m[3] += mat.m[3];
m[4] += mat.m[4];
m[5] += mat.m[5];
m[6] += mat.m[6];
m[7] += mat.m[7];
m[8] += mat.m[8];
return *this;
}
/**
* Transposes this matrix in place. Returns this matrix for chaining
* 转置矩阵
*
* @return This matrix after transpose
*/
Mat3& Mat3::transposeLocal() {
float tmp[9];
get(tmp, false);
set(tmp, true);
return *this;
}
/**
* Inverts this matrix and stores it in the given store.
* 逆矩阵,保存在参数中,不改变自身
*
* @return The store
*/
Mat3 Mat3::invertNew(void) {
Mat3 store;
float det = determinant();
if (std::abs(det) <= 0)
return store.zero();
store.m[0] = m[4] * m[8] - m[5] * m[7];
store.m[1] = m[2] * m[7] - m[1] * m[8];
store.m[2] = m[1] * m[5] - m[2] * m[4];
store.m[3] = m[5] * m[6] - m[3] * m[8];
store.m[4] = m[0] * m[8] - m[2] * m[6];
store.m[5] = m[2] * m[3] - m[0] * m[5];
store.m[6] = m[3] * m[7] - m[4] * m[6];
store.m[7] = m[1] * m[6] - m[0] * m[7];
store.m[8] = m[0] * m[4] - m[1] * m[3];
store.multLocal(1 / det);
return store;
}
/**
* Inverts this matrix locally.
* 逆矩阵,改变自身
*
* @return this
*/
Mat3& Mat3::invertLocal() {
float det = determinant();
if (std::abs(det) <= FLT_EPSILON)
return zero();
float f00 = m[4] * m[8] - m[5] * m[7];
float f01 = m[2] * m[7] - m[1] * m[8];
float f02 = m[1] * m[5] - m[2] * m[4];
float f10 = m[5] * m[6] - m[3] * m[8];
float f11 = m[0] * m[8] - m[2] * m[6];
float f12 = m[2] * m[3] - m[0] * m[5];
float f20 = m[3] * m[7] - m[4] * m[6];
float f21 = m[1] * m[6] - m[0] * m[7];
float f22 = m[0] * m[4] - m[1] * m[3];
m[0] = f00;
m[1] = f01;
m[2] = f02;
m[3] = f10;
m[4] = f11;
m[5] = f12;
m[6] = f20;
m[7] = f21;
m[8] = f22;
multLocal(1 / det);
return *this;
}
/**
* Places the adjoint of this matrix in store (creates store if null.)
* 伴随矩阵
*
* @param store
* The matrix to store the result in. If null, a new matrix is
* created.
* @return store
*/
Mat3 Mat3::adjoint() {
Mat3 store;
store.m[0] = m[4] * m[8] - m[5] * m[7];
store.m[1] = m[2] * m[7] - m[1] * m[8];
store.m[2] = m[1] * m[5] - m[2] * m[4];
store.m[3] = m[5] * m[6] - m[3] * m[8];
store.m[4] = m[0] * m[8] - m[2] * m[6];
store.m[5] = m[2] * m[3] - m[0] * m[5];
store.m[6] = m[3] * m[7] - m[4] * m[6];
store.m[7] = m[1] * m[6] - m[0] * m[7];
store.m[8] = m[0] * m[4] - m[1] * m[3];
return store;
}
/**
* determinant generates the determinate of this matrix.
* 矩阵的行列式
*
* @return the determinate
*/
float Mat3::determinant() {
float fCo00 = m[4] * m[8] - m[5] * m[7];
float fCo10 = m[5] * m[6] - m[3] * m[8];
float fCo20 = m[3] * m[7] - m[4] * m[6];
float fDet = m[0] * fCo00 + m[1] * fCo10 + m[2] * fCo20;
return fDet;
}
/**
* Sets all of the values in this matrix to zero.
* 重置矩阵各元素置为0
*
* @return this matrix
*/
Mat3& Mat3::zero() {
m[0] = m[1] = m[2] = m[3] = m[4] = m[5] = m[6] = m[7] = m[8] = 0.0f;
return *this;
}
/**
* transposeNew returns a transposed version of this matrix.
* 转置矩阵
*
* @return The new Mat3 object.
*/
Mat3 Mat3::transposeNew() {
float temp[9] = { m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8] };
return Mat3(temp);
}
/**
* are these two matrices the same? they are is they both have the same mXX
* values.
*
* @param o
* the object to compare for equality
* @return true if they are equal
*/
bool Mat3::equals(const Mat3& o) const {
return memcmp(&o, this, sizeof(o)) == 0;
}
/**
* A function for creating a rotation matrix that rotates a vector called
* "start" into another vector called "end".
* 创建一个旋转矩阵从向量start旋转到end
*
* @param start
* normalized non-zero starting vector
* @param end
* normalized non-zero ending vector
* @see "Tomas M?ller, John Hughes /"Efficiently Building a Matrix to Rotate
* / One Vector to Another/" Journal of Graphics Tools, 4(4):1-4, 1999"
*/
void Mat3::fromStartEndVectors(cocos2d::Vec3 start, cocos2d::Vec3 end) {
cocos2d::Vec3 v;
float e, h, f;
cocos2d::Vec3::cross(start, end, &v);
e = start.dot(end);
f = (e < 0) ? -e : e;
// if "from" and "to" vectors are nearly parallel
if (f > 1.0f - FLT_EPSILON) {
cocos2d::Vec3 u;
cocos2d::Vec3 x;
float c1, c2, c3; /* coefficients for later use */
int i, j;
x.x = (start.x > 0.0) ? start.x : -start.x;
x.y = (start.y > 0.0) ? start.y : -start.y;
x.z = (start.z > 0.0) ? start.z : -start.z;
if (x.x < x.y) {
if (x.x < x.z) {
x.x = 1.0f;
x.y = x.z = 0.0f;
}
else {
x.z = 1.0f;
x.x = x.y = 0.0f;
}
}
else {
if (x.y < x.z) {
x.y = 1.0f;
x.x = x.z = 0.0f;
}
else {
x.z = 1.0f;
x.x = x.y = 0.0f;
}
}
u.x = x.x - start.x;
u.y = x.y - start.y;
u.z = x.z - start.z;
v.x = x.x - end.x;
v.y = x.y - end.y;
v.z = x.z - end.z;
c1 = 2.0f / u.dot(u);
c2 = 2.0f / v.dot(v);
c3 = c1 * c2 * u.dot(v);
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
float val = -c1 * (&u.x)[i] * (&u.x)[j] - c2 * (&v.x)[i]
* (&v.x)[j] + c3 * (&v.x)[i] * (&u.x)[j];
set(i, j, val);
}
float val = get(i, i);
set(i, i, val + 1.0f);
}
}
else {
// the most common case, unless "start"="end", or "start"=-"end"
float hvx, hvz, hvxy, hvxz, hvyz;
h = 1.0f / (1.0f + e);
hvx = h * v.x;
hvz = h * v.z;
hvxy = hvx * v.y;
hvxz = hvx * v.z;
hvyz = hvz * v.y;
set(0, 0, e + hvx * v.x);
set(0, 1, hvxy - v.z);
set(0, 2, hvxz + v.y);
set(1, 0, hvxy + v.z);
set(1, 1, e + h * v.y * v.y);
set(1, 2, hvyz - v.x);
set(2, 0, hvxz - v.y);
set(2, 1, hvyz + v.x);
set(2, 2, e + hvz * v.z);
}
}
/**
* scale scales the operation performed by this matrix on a
* per-component basis.
* 标量乘行向量,各列分别相乘
*
* @param scale
* The scale applied to each of the X, Y and Z output values.
*/
void Mat3::scale(const cocos2d::Vec3& scale) {
m[0] *= scale.x;
m[3] *= scale.x;
m[6] *= scale.x;
m[1] *= scale.y;
m[4] *= scale.y;
m[7] *= scale.y;
m[2] *= scale.z;
m[5] *= scale.z;
m[8] *= scale.z;
}
bool Mat3::equalIdentity(const Mat3& mat) {
if (std::abs(mat.m[0] - 1) > 1e-4)
return false;
if (std::abs(mat.m[4] - 1) > 1e-4)
return false;
if (std::abs(mat.m[8] - 1) > 1e-4)
return false;
if (std::abs(mat.m[1]) > 1e-4)
return false;
if (std::abs(mat.m[2]) > 1e-4)
return false;
if (std::abs(mat.m[3]) > 1e-4)
return false;
if (std::abs(mat.m[5]) > 1e-4)
return false;
if (std::abs(mat.m[6]) > 1e-4)
return false;
if (std::abs(mat.m[7]) > 1e-4)
return false;
return true;
}
NS_CC_MATH_END