📄 vmath
字号:
// ---------------------------------------------------------------------------------------------------------------------------------
// _ _
// | | | |
// __ ___ __ ___ __ _| |_| |__
// \ \ / / '_ ` _ \ / _` | __| '_ \
// \ V /| | | | | | (_| | |_| | | |
// \_/ |_| |_| |_|\__,_|\__|_| |_|
//
// Description:
//
// Generic 2-dimensional NxM matrix/vector mathematics class specialized for 3D usage
//
// Notes:
//
// Best viewed with 8-character tabs and (at least) 132 columns
//
// History:
//
// 04/13/2001 by Paul Nettle: Original creation
//
// Restrictions & freedoms pertaining to usage and redistribution of this software:
//
// This software is 100% free. If you use this software (in part or in whole) you must credit the author. This software may not be
// re-distributed (in part or in whole) in a modified form without clear documentation on how to obtain a copy of the original
// work. You may not use this software to directly or indirectly cause harm to others. This software is provided as-is and without
// warrantee -- Use at your own risk. For more information, visit HTTP://www.FluidStudios.com/
//
// IMPORTANT:
//
// Due to the nature of this class being a single solution for all 2D matrices of NxM size (which includes matrices, vectors &
// points) there are two cases where the class's behavior does not make as much sense as you might like. These two cases are in
// reference to the >> and ^ operators.
//
// A multiplication operator is commonly used for component-wise multiplication, dot products and matrix concatenation. Since the
// class supports the operators [+, -, /, *, +=, -=, /=, *=] it was prudent to maintain consistency and let operator* and
// operator *= work as component-wise multiplication. So what operators should be used for dot products and concatenation? I have
// chosen >> for concatenation, because it helps to serve as a reminder in which direction the operation's associativity goes
// (from left-to-right). The dot product uses operator ^ (simply for lack of a better operator.)
//
// The problem you may find then, is that operator >> and operator ^ have lower precedence than addition & subtraction. Without
// the use of parenthesis around these multiplicative operations, you will not get the result you expect.
//
// Furthermore, operator ^ (dot product) has a lower precedence than even operators [<, <=, >, >=]. This can cause prolems in
// cases like: "if (v1 ^ v2 > 0)".
//
// If you do not like the operators I have chosen, feel free to modify them. Or you may chose to perform these operations through
// the function calls dot(), concat(), cross(), etc.
//
// Consider yourself warned.
//
// Copyright 2001, Fluid Studios, Inc., all rights reserved.
// ---------------------------------------------------------------------------------------------------------------------------------
#ifndef _GEOM_VMATH
#define _GEOM_VMATH
// ---------------------------------------------------------------------------------------------------------------------------------
// Module setup (required includes, macros, etc.)
// ---------------------------------------------------------------------------------------------------------------------------------
#include <cmath>
#include "common"
#include "../../Include/fstl/fstl"
GEOM_NAMESPACE_BEGIN
// ---------------------------------------------------------------------------------------------------------------------------------
// Define a matrix that is N columns wide and M rows tall. This matrix is row-major.
//
// N can be thought of as the [N]umber of elements per vector, and M can be thought of as the number of vectors in the matrix
// ---------------------------------------------------------------------------------------------------------------------------------
template <unsigned int N, unsigned int M, class T = GEOM_TYPE>
class Matrix
{
public:
// Default constructor
inline Matrix() {}
// Copy constructor
inline Matrix(const Matrix & m)
{
fstl::memcpy(_data, m._data, N*M);
}
// Initialize with three vectors
inline Matrix(const Matrix<N, 1, T> & xv, const Matrix<N, 1, T> & yv, const Matrix<N, 1, T> & zv)
{
setXVector(xv);
setYVector(yv);
setZVector(zv);
}
// Initialize with four values (useful for vectors)
inline Matrix(const T & xv, const T & yv, const T & zv, const T & wv)
{
// This assertion guarantees that they are initializing the entire vector
TemplateAssert(N == 4 && M == 1);
x() = xv;
y() = yv;
z() = zv;
w() = wv;
}
// Initialize with three values (useful for vectors)
inline Matrix(const T & xv, const T & yv, const T & zv)
{
// This assertion guarantees that they are initializing the entire vector
TemplateAssert(N == 3 && M == 1);
x() = xv;
y() = yv;
z() = zv;
}
// Initialize with two values (useful for vectors)
inline Matrix(const T & xv, const T & yv)
{
// This assertion guarantees that they are initializing the entire vector
TemplateAssert(N == 2 && M == 1);
x() = xv;
y() = yv;
}
// These are handy 2D/3D/4D casts
inline operator Matrix<2, 1, T>()
{
TemplateAssert(M == 1);
Matrix<2, 1, T> result;
result.fill(0);
int c = N;
if (c > 2) c = 2;
for (int i = 0; i < c; i++) result(i,0) = (*this)(i,0);
return result;
}
inline operator Matrix<3, 1, T>()
{
TemplateAssert(M == 1);
Matrix<3, 1, T> result;
result.fill(0);
int c = N;
if (c > 3) c = 3;
for (int i = 0; i < c; i++) result(i,0) = (*this)(i,0);
return result;
}
inline operator Matrix<4, 1, T>()
{
TemplateAssert(M == 1);
Matrix<4, 1, T> result;
result.fill(0);
result.w() = static_cast<T>(1);
int c = N;
if (c > 4) c = 4;
for (int i = 0; i < c; i++) result(i,0) = (*this)(i,0);
return result;
}
// Return a zero'd matrix
static Matrix zero()
{
Matrix result;
result.fill(static_cast<T>(0));
return result;
}
// The infamous 'operator='
inline Matrix & operator =(const Matrix & m)
{
if (&m != this) fstl::memcpy(_data, m._data, N*M);
return *this;
}
// Indexing: format = i down, j across
inline const T & operator()(const unsigned int i, const unsigned int j) const
{
return _data[j*N+i];
}
// Indexing: format = i down, j across
inline T & operator()(const unsigned int i, const unsigned int j)
{
return _data[j*N+i];
}
// Matrix concatenation
//
// Specialized to follow the rules of matrix multiplication, for NxM * OxP:
// where M must be equal to O and resulting matrix is NxP. Otherwise, a
// compiler error will occur.
//
// Note that we use the >> operator. This is because of the lack of available
// operators, and also it serves as a reminder that the operations are from
// left-to-right (the convenient way.)
// I'm pretty sure this is wrong (I've seen it crash), so it's conditionally compiled out. Although, given the time, I would
// like to do things this way instad...
#if 0
template <unsigned int P>
inline const Matrix<N, P, T> operator >>(const Matrix<M, P, T> & m) const {return concat(m);}
template <unsigned int P>
inline const Matrix<N, P, T> operator >>=(const Matrix<M, P, T> & m) {*this = concat(m); return *this;}
template <unsigned int P>
inline const Matrix<N, P, T> concat(const Matrix<M, P, T> & m) const
{
Matrix<N, P, T> result;
result.fill(static_cast<T>(0));
for (unsigned int i = 0; i < N; i++)
for (unsigned int j = 0; j < M; j++)
for (unsigned int k = 0; k < P; k++)
result(i,j) += (*this)(i,k) * m(k,j);
return result;
}
#else
// We're doing matrix*vector, which, as far as I can tell, doesn't work the same as vector*vector. Though, it would work the same
// if it was vector*matrix... so this sucker is specialized for that purpose
inline const Matrix<N, 1, T> operator >>(const Matrix<M, 1, T> & m) const {return concat(m);}
inline const Matrix<N, 1, T> operator >>=(const Matrix<M, 1, T> & m) {*this = concat(m); return *this;}
inline const Matrix<N, 1, T> concat(const Matrix<M, 1, T> & m) const
{
Matrix<N, 1, T> result;
result.fill(static_cast<T>(0));
for (unsigned int i = 0; i < N; i++)
for (unsigned int j = 0; j < M; j++)
result(i,0) += (*this)(j,i) * m(j,0);
return result;
}
inline const Matrix<N, 2, T> operator >>(const Matrix<M, 2, T> & m) const {return concat(m);}
inline const Matrix<N, 2, T> operator >>=(const Matrix<M, 2, T> & m) {*this = concat(m); return *this;}
inline const Matrix<N, 2, T> concat(const Matrix<M, 2, T> & m) const
{
Matrix<N, 2, T> result;
result.fill(static_cast<T>(0));
for (unsigned int i = 0; i < N; i++)
for (unsigned int j = 0; j < M; j++)
for (unsigned int k = 0; k < 2; k++)
result(i,j) += (*this)(i,k) * m(k,j);
return result;
}
inline const Matrix<N, 3, T> operator >>(const Matrix<M, 3, T> & m) const {return concat(m);}
inline const Matrix<N, 3, T> operator >>=(const Matrix<M, 3, T> & m) {*this = concat(m); return *this;}
inline const Matrix<N, 3, T> concat(const Matrix<M, 3, T> & m) const
{
Matrix<N, 3, T> result;
result.fill(static_cast<T>(0));
for (unsigned int i = 0; i < N; i++)
for (unsigned int j = 0; j < M; j++)
for (unsigned int k = 0; k < 3; k++)
result(i,j) += (*this)(i,k) * m(k,j);
return result;
}
inline const Matrix<N, 4, T> operator >>(const Matrix<M, 4, T> & m) const {return concat(m);}
inline const Matrix<N, 4, T> operator >>=(const Matrix<M, 4, T> & m) {*this = concat(m); return *this;}
inline const Matrix<N, 4, T> concat(const Matrix<M, 4, T> & m) const
{
Matrix<N, 4, T> result;
result.fill(static_cast<T>(0));
for (unsigned int i = 0; i < N; i++)
for (unsigned int j = 0; j < M; j++)
for (unsigned int k = 0; k < 4; k++)
result(i,j) += (*this)(i,k) * m(k,j);
return result;
}
#endif
// 3D Vector cross product
//
// Note that the cross product is specifically a 3-dimensional operation. So this routine
// will fill the remaining elements (if any) with the contents of this->_data[...]
//
// Specialized for Nx1 matrices (i.e. vectors)
inline void cross(const Matrix<N, 1, T> & m)
{
TemplateAssert(N >= 3);
T tx = y() * m.z() - z() * m.y();
T ty = z() * m.x() - x() * m.z();
T tz = x() * m.y() - y() * m.x();
x() = tx;
y() = ty;
z() = tz;
}
inline const Matrix<N, 1, T> operator %(const Matrix<N, 1, T> & m) const
{
Matrix<N, 1, T> result = *this;
result.cross(m);
return result;
}
inline const Matrix operator %=(const Matrix & m)
{
cross(m);
return *this;
}
// Vector dot product
//
// Specialized for Nx1 matrices (i.e. vectors)
inline const T dot(const Matrix<N, 1, T> & m) const
{
T result = static_cast<T>(0);
for (unsigned int i = 0; i < N; i++) result += _data[i] * m.data()[i];
return result;
}
inline const T operator ^(const Matrix<N, 1, T> & m) const
{
return dot(m);
}
// Component-wise multiplication with matrix
inline const Matrix operator *(const Matrix & m) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] * m._data[i];
return result;
}
// Component-wise multiplication with scalar
inline const Matrix operator *(const T & value) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] * value;
return result;
}
// Component-wise multiplication with matrix (into self)
inline const Matrix operator *=(const Matrix & m)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] *= m._data[i];
return *this;
}
// Component-wise multiplication with scalar (into self)
inline const Matrix operator *=(const T & value)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] *= value;
return *this;
}
// Component-wise division with matrix
inline const Matrix operator /(const Matrix & m) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] / m._data[i];
return result;
}
// Component-wise division with scalar
inline const Matrix operator /(const T & value) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] / value;
return result;
}
// Component-wise division with scalar (scalar / component)
inline const Matrix inverseDivide(const T & value) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = value / _data[i];
return result;
}
// Component-wise division with matrix (into self)
inline const Matrix operator /=(const Matrix & m)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] /= m._data[i];
return *this;
}
// Component-wise division with scalar (into self)
inline const Matrix operator /=(const T & value)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] /= value;
return *this;
}
// Component-wise addition with matrix
inline const Matrix operator +(const Matrix & m) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] + m._data[i];
return result;
}
// Component-wise addition with scalar
inline const Matrix operator +(const T & value) const
{
Matrix result;
for (unsigned int i = 0; i < N*M; i++) result._data[i] = _data[i] + value;
return result;
}
// Component-wise addition with matrix (into self)
inline const Matrix operator +=(const Matrix & m)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] += m._data[i];
return *this;
}
// Component-wise addition with scalar (into self)
inline const Matrix operator +=(const T & value)
{
for (unsigned int i = 0; i < N*M; i++) _data[i] += value;
return *this;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -