working a bit to get the constructor usage cleaned up for the whole matrix code

This commit is contained in:
Hartmut Seichter 2019-01-21 15:46:57 +01:00
parent f33e6769f4
commit bf834a33e0
11 changed files with 293 additions and 163 deletions

View file

@ -7,8 +7,8 @@ set(hdrs
include/pw/core/matrixbase.hpp
include/pw/core/matrix.hpp
include/pw/core/vector.hpp
# include/pw/core/quaternion.hpp
# include/pw/core/serialize.hpp
include/pw/core/quaternion.hpp
include/pw/core/serialize.hpp
include/pw/core/image.hpp
include/pw/core/point.hpp
include/pw/core/rect.hpp
@ -25,7 +25,7 @@ set(srcs
src/debug.cpp
src/mesh.cpp
src/core.cpp
# src/serialize.cpp
src/serialize.cpp
src/timer.cpp
src/image.cpp
${CMAKE_SOURCE_DIR}/README.md

View file

@ -29,23 +29,27 @@
#include <numeric>
namespace pw {
template <typename T, std::size_t R,std::size_t C,bool RowMajor = false>
struct matrix_ : matrixbase_<T, matrix_<T, R, C>> {
T data[R*C];
matrix_() = default;
typedef matrixbase_<T, matrix_<T, R, C>> Base;
using Base::Base;
matrix_(const matrix_<T,R,C,RowMajor>& other)
matrix_(const matrix_& other)
{
*this = other;
}
explicit matrix_(std::initializer_list<T> args)
{
typename std::initializer_list<T>::iterator it = args.begin();
for (;it != args.end();it++) data[it-args.begin()] = *it;
}
matrix_& operator = (const matrix_<T,R,C,RowMajor>& other)
{
for (size_t i = 0; i < other.size();i++) (*this)[i] = other[i];
@ -53,11 +57,11 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> {
}
template <typename... Arguments>
matrix_(Arguments ...values)
: data {values... }
matrix_& set(Arguments ...values)
{
static_assert(sizeof...(Arguments) == R*C,
"Incorrect number of arguments");
static_assert(sizeof...(Arguments) == R*C, "Incorrect number of arguments");
data = {values... };
return *this;
}
//! rows
@ -81,12 +85,14 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> {
return data[offset(r,c)];
}
inline const T* ptr() const { return &data[0]; }
//! set identity
inline matrix_& set_identity()
{
for (unsigned int r = 0;r < rows(); r++)
for (unsigned int c = 0; c < cols(); c++)
this->at(r,c) = (c == r) ? T(1) : T(0);
(*this)(r,c) = (c == r) ? T(1) : T(0);
return *this;
}
@ -167,6 +173,22 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> {
inline bool square() const { return R == C; }
inline const matrix_ operator + (const matrix_ &other) const {
matrix_ res(*this);
for (size_t r = 0; r < R;r++)
for (size_t c = 0; c < C;c++)
res(r,c) += other(r,c);
return res;
}
inline const matrix_ operator - (const matrix_ &other) const {
matrix_ res(*this);
for (size_t r = 0; r < R;r++)
for (size_t c = 0; c < C;c++)
res(r,c) -= other(r,c);
return res;
}
};
template <> inline
@ -218,6 +240,35 @@ using matrix4x4f = matrix_<float, 4, 4>;
using matrix4x4d = matrix_<double, 4, 4>;
using matrix4x4 = matrix_<real_t, 4, 4>;
//
//
//
template <typename T>
struct matrix_tools {
inline static
matrix4x4_<T> projection_from_frustum(T Left,T Right,T Bottom,T Top,T zNear,T zFar)
{
matrix4x4_<T> frustum;
frustum.fill(0);
frustum(0,0) = T(2) * zNear/(Right-Left);
frustum(1,1) = T(2) * zNear/(Top-Bottom);
frustum(0,2) = (Right+Left)/(Right-Left); //A
frustum(1,2) = (Top+Bottom)/(Top-Bottom); //B
frustum(2,2) = - (zFar+zNear)/(zFar-zNear); //C
frustum(3,2) = -(T(2) * zFar*zNear)/(zFar-zNear); //D
frustum(2,3) = -T(1);
return frustum;
}
};
}

View file

@ -38,6 +38,9 @@ namespace pw {
template <typename T, typename Derived>
struct matrixbase_ {
typedef T value_type;
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
@ -54,11 +57,6 @@ struct matrixbase_ {
return derived().fill(0);
}
T trace() const {
return std::accumulate(std::begin(derived().data),std::end(derived().data),T(0));
}
inline T squared_norm() const {
return std::accumulate(std::begin(derived().data),std::end(derived().data), T(0),
[&](const T& a,const T& b){
@ -70,9 +68,8 @@ struct matrixbase_ {
return std::sqrt(squared_norm());
}
inline Derived& normalize() {
(*this) /= this->norm();
return derived();
inline const Derived normalized() const {
return *this / this->norm() ;
}
using iterator = T*;
@ -90,11 +87,15 @@ struct matrixbase_ {
return derived().data[i];
}
inline Derived& operator *= (const T& b) { for (auto & e : *this) e *= b; return derived(); }
inline Derived& operator /= (const T& b) { for (auto & e : *this) e /= b; return derived(); }
inline Derived& operator += (const T& b) { for (auto & e : *this) e += b; return derived(); }
inline Derived& operator -= (const T& b) { for (auto & e : *this) e -= b; return derived(); }
// inline Derived& operator *= (const T& b) { for (auto & e : *this) e *= b; return derived(); }
// inline Derived& operator /= (const T& b) { for (auto & e : *this) e /= b; return derived(); }
// inline Derived& operator += (const T& b) { for (auto & e : *this) e += b; return derived(); }
// inline Derived& operator -= (const T& b) { for (auto & e : *this) e -= b; return derived(); }
inline const Derived operator * (const T& b) const { Derived r(derived()); for (auto & e : r) e *= b; return r; }
inline const Derived operator / (const T& b) const { Derived r(derived()); for (auto & e : r) e /= b; return r; }
inline const Derived operator + (const T& b) const { Derived r(derived()); for (auto & e : r) e += b; return r; }
inline const Derived operator - (const T& b) const { Derived r(derived()); for (auto & e : r) e -= b; return r; }
};

View file

@ -20,14 +20,109 @@
* SOFTWARE.
*
*/
#ifndef TP_CORE_QUATERNION_HPP
#define TP_CORE_QUATERNION_HPP
#ifndef PW_CORE_QUATERNION_HPP
#define PW_CORE_QUATERNION_HPP
#include <pw/core/vector.hpp>
#include <pw/core/matrix.hpp>
namespace pw {
/**
* simplified quaternion class
*/
template <typename T>
struct quaternion_ : vector4_<T> {
typedef vector4_<T> Base;
using Base::Base;
using Base::x;
using Base::y;
using Base::z;
using Base::w;
// using Base::lerp;
// using Base::operator*;
// using Base::operator/;
inline const quaternion_ operator * (const quaternion_& rhs) const {
return quaternion_(
rhs.w()*x() + rhs.x()*w() + rhs.y()*z() - rhs.z()*y(),
rhs.w()*y() - rhs.x()*z() + rhs.y()*w() + rhs.z()*x(),
rhs.w()*z() + rhs.x()*y() - rhs.y()*x() + rhs.z()*w(),
rhs.w()*w() - rhs.x()*x() - rhs.y()*y() - rhs.z()*z()
);
}
//! conjugate
inline quaternion_ conjugate() const { return quaternion_( { -x(),-y(),-z(),w() } ); }
//! compute inverse
inline auto inverse() const {
return conjugate() / this->norm();
}
const matrix4x4_<T> to_matrix() const {
matrix4x4_<T> m; m.set_identity();
T xx = x() * x();
T xy = x() * y();
T xz = x() * z();
T xw = x() * w();
T yy = y() * y();
T yz = y() * z();
T yw = y() * w();
T zz = z() * z();
T zw = z() * w();
m(0,0) = 1 - 2 * ( yy + zz );
m(0,1) = 2 * ( xy - zw );
m(0,2) = 2 * ( xz + yw );
m(1,0) = 2 * ( xy + zw );
m(1,1) = 1 - 2 * ( xx + zz );
m(1,2) = 2 * ( yz - xw );
m(2,0) = 2 * ( xz - yw );
m(2,1) = 2 * ( yz + xw );
m(2,2) = 1 - 2 * ( xx + yy );
return m;
}
static quaternion_<T> from_matrix(const matrix_<T,4,4> &m) {
using std::sqrt;
const T wtemp = sqrt(T(1) + m(0,0) + m(1,1) + m(2,2)) / T(2);
const T w4 = T(4.0) * wtemp;
return quaternion_<T>(
(m(2,1) - m(1,2)) / w4,
(m(0,2) - m(2,0)) / w4,
(m(1,0) - m(0,1)) / w4,
wtemp);
}
static const quaternion_ normalized_lerp(const quaternion_ &a,const quaternion_ &b,const T &t) {
return quaternion_(lerp(a,b,t).normalized());
}
};
//
//
//
typedef quaternion_<real_t> quaternion;
typedef quaternion_<float> quaternionf;
typedef quaternion_<double> quaterniond;
}
#if 0
/**
* simplified quaternion class
*/
@ -104,16 +199,10 @@ public:
inline const T norm() const { return _q.norm(); }
//! dot product
inline const T dot(const quaternion_& other) const { return _q.dot(other._q); }
inline const T dot(const quaternion_& other) const { return dot(_q,other._q); }
//! conjugate
inline quaternion_ conjugate() const { return quaternion_(-x(),-y(),-z(),w()); }
//! compute inverse
inline quaternion_ inverse() const {
const T one_over_squared_norm = T(1) / squared_norm();
return conjugate() * one_over_squared_norm;
}
//! compute normalized
inline quaternion_ normalized() const {
@ -169,52 +258,9 @@ template <typename T>
const T quaternion_<T>::_sqrt90 = std::sqrt(0.5);
template <typename T>
const quaternion_<T> quaternion_<T>::from_matrix(const matrix_<T,4,4> &m) {
using std::sqrt;
T wtemp = sqrt(T(1) + m.at(0,0) + m.at(1,1) + m.at(2,2)) / T(2.0);
const T w4 = T(4.0) * wtemp;
return quaternion_<T>(
(m.at(2,1) - m.at(1,2)) / w4,
(m.at(0,2) - m.at(2,0)) / w4,
(m.at(1,0) - m.at(0,1)) / w4,
wtemp);
}
template <typename T>
const matrix_<T,4,4> quaternion_<T>::to_matrix() const {
matrix_<T,4,4> m; m.set_identity();
T xx = x() * x();
T xy = x() * y();
T xz = x() * z();
T xw = x() * w();
T yy = y() * y();
T yz = y() * z();
T yw = y() * w();
T zz = z() * z();
T zw = z() * w();
m.at(0,0) = 1 - 2 * ( yy + zz );
m.at(0,1) = 2 * ( xy - zw );
m.at(0,2) = 2 * ( xz + yw );
m.at(1,0) = 2 * ( xy + zw );
m.at(1,1) = 1 - 2 * ( xx + zz );
m.at(1,2) = 2 * ( yz - xw );
m.at(2,0) = 2 * ( xz - yw );
m.at(2,1) = 2 * ( yz + xw );
m.at(2,2) = 1 - 2 * ( xx + yy );
return m;
}
template <typename T>
const quaternion_<T> quaternion_<T>::identity()
@ -257,15 +303,7 @@ const quaternion_<T> quaternion_<T>::rotate_90_degree_around_z(bool negative/* =
return quaternion_<T>(0,0,(negative) ? -_sqrt90 : _sqrt90, _sqrt90);
}
template <typename T>
const quaternion_<T> quaternion_<T>::lerp(const quaternion_<T>& qa,const quaternion_<T>& qb,const T& t) {
return quaternion_<T>(qa + (qb - qa) * t);
}
template <typename T>
const quaternion_<T> quaternion_<T>::normalized_lerp(const quaternion_<T>& qa,const quaternion_<T>& qb,const T& t) {
return quaternion_<T>::lerp(qa,qb,t).normalized();
}
template <typename T>
const quaternion_<T> quaternion_<T>::slerp(const quaternion_<T>& qa,const quaternion_<T>& qb,const T& t)
@ -306,14 +344,9 @@ const quaternion_<T> quaternion_<T>::slerp(const quaternion_<T>& qa,const quater
return qm;
}
//
//
//
typedef quaternion_<real_t> quaternion;
typedef quaternion_<float> quaternionf;
typedef quaternion_<double> quaterniond;
}
#endif
#endif

View file

@ -39,7 +39,7 @@ struct serialize {
for (int r = 0; r < m.rows();r++) {
for (int c = 0; c < m.cols();c++) {
ss << m.at(r,c) << " ";
ss << m(r,c) << " ";
}
ss << std::endl;
}

View file

@ -28,40 +28,44 @@
namespace pw {
template <typename T, std::size_t N,bool RowMajor = false>
struct vector_ : matrix_<T, N, 1, RowMajor>
template <typename T, std::size_t N>
struct vector_ : matrix_<T, N, 1,false>
{
typedef matrix_<T, N, 1, RowMajor> derived_type;
typedef matrix_<T, N, 1, false> Base;
vector_() = default;
vector_(const derived_type& rhs) : derived_type(rhs) {}
using typename Base::value_type;
using Base::Base;
template <typename... Arguments>
vector_(Arguments ...values)
: derived_type( { values...} )
{
static_assert(sizeof...(Arguments) == N,
"Incorrect number of arguments");
static T dot(const vector_ &a,const vector_ &b) {
vector_ r; for (size_t i = 0;i < N;i++) r[i] = a[i] * b[i];
return std::accumulate(std::begin(r), std::end(r), T(0));
}
static T angle_between(const vector_ &a,const vector_ &b) {
return std::acos( dot( a.normalized(), b.normalized() ) );
}
static const vector_ lerp(const vector_ &a,const vector_ &b,const T& t) {
return a + (b - a) * t;
}
};
template <typename T, typename U, std::size_t N,bool RowMajor = false>
auto operator * (const vector_<T, N, RowMajor>& a, const vector_<U, N, RowMajor>& b)
-> vector_<decltype(a[0] * b[0]), N, RowMajor> {
vector_<decltype(a[0] * b[0]), N, RowMajor> result;
for (std::size_t i = 0; i < N; ++i) {
result[i] = a[i] * b[i];
}
return result;
}
template <typename T>
struct vector2_ : vector_<T,2> {
template <typename T, typename U, std::size_t N,bool RowMajor = false>
auto dot(const vector_<T, N, RowMajor>& a, const vector_<U, N, RowMajor>& b)
-> decltype(a[0] * b[0]) {
auto product = a * b;
using V = decltype(product.x);
return std::accumulate(std::begin(product), std::end(product), V(0));
}
using vector_<T,2>::vector_;
inline const T& x() const { return (*this)[0]; }
inline T& x() { return (*this)[0]; }
inline const T& y() const { return (*this)[1]; }
inline T& y() { return (*this)[1]; }
inline auto homogenous(T w = 1) const { return vector_<T,3>(x(),y(),w); }
};
template <typename T>
@ -69,24 +73,55 @@ struct vector3_ : vector_<T,3> {
using vector_<T,3>::vector_;
inline static vector3_<T> forward() { return vector3_<T> ( T(0), T(0),-T(1) ); }
inline static vector3_<T> backward() { return vector3_<T>( T(0), T(0), T(1) ); }
inline static vector3_<T> right() { return vector3_<T> ( T(1), T(0), T(0) ); }
inline static vector3_<T> left() { return vector3_<T> ( -T(1), T(0), T(0) ); }
inline static vector3_<T> up() { return vector3_<T> ( T(0), T(1), T(0) ); }
inline static vector3_<T> down() { return vector3_<T> ( T(0),-T(1), T(0) ); }
inline const T& x() const { return (*this)[0]; }
inline T& x() { return (*this)[0]; }
inline const T& y() const { return (*this)[1]; }
inline T& y() { return (*this)[1]; }
inline const T& z() const { return (*this)[2]; }
inline T& z() { return (*this)[2]; }
inline auto xy() const { return vector2_( { x(),y() } ); }
inline auto homogenous(T w = 1) const { return vector_<T,4>( { x(),y(),z(),w } ); }
inline static vector3_<T> forward() { return vector3_<T> ( { T(0), T(0),-T(1) } ); }
inline static vector3_<T> backward() { return vector3_<T>( { T(0), T(0), T(1) } ); }
inline static vector3_<T> right() { return vector3_<T> ( { T(1), T(0), T(0) } ); }
inline static vector3_<T> left() { return vector3_<T> ( {-T(1), T(0), T(0) } ); }
inline static vector3_<T> up() { return vector3_<T> ( { T(0), T(1), T(0) } ); }
inline static vector3_<T> down() { return vector3_<T> ( { T(0),-T(1), T(0) } ); }
};
template <typename T>
struct vector4_ : vector_<T,4> {
using vector_<T,4>::vector_;
inline const T& x() const { return (*this)[0]; }
inline T& x() { return (*this)[0]; }
inline const T& y() const { return (*this)[1]; }
inline T& y() { return (*this)[1]; }
inline const T& z() const { return (*this)[2]; }
inline T& z() { return (*this)[2]; }
inline const T& w() const { return (*this)[3]; }
inline T& w() { return (*this)[3]; }
inline auto xyz() const { return vector3_<T>({ x(),y(),z() } ); }
inline auto project() const { return vector3_<T>({ x()/w(),y()/w(),z()/w() } ); }
};
//
//
//
template <typename T> using vector2_ = vector_<T, 2>;
//template <typename T> using vector3_ = vector_<T, 3>;
template <typename T> using vector4_ = vector_<T, 4>;
using vector2f = vector2_<float>;
using vector2d = vector2_<double>;
using vector2 = vector2_<real_t>;
@ -104,7 +139,7 @@ using vector4 = vector4_<real_t>;
#if ___OLDSTUFF
#if defined(___OLDSTUFF)
template <unsigned int components,typename T>
class vector_ : public matrix_<components,1,T> {

View file

@ -5,20 +5,20 @@ add_executable(pwcore_test_matrix
target_link_libraries(pwcore_test_matrix
pwcore)
#add_executable(pwcore_test_vector
# pwcore_test_vector.cpp
# )
add_executable(pwcore_test_vector
pwcore_test_vector.cpp
)
#target_link_libraries(pwcore_test_vector
# pwcore)
target_link_libraries(pwcore_test_vector
pwcore)
#add_executable(pwcore_test_quaternion
# pwcore_test_quaternion.cpp
# )
add_executable(pwcore_test_quaternion
pwcore_test_quaternion.cpp
)
#target_link_libraries(pwcore_test_quaternion
# pwcore)
target_link_libraries(pwcore_test_quaternion
pwcore)
add_executable(pwcore_test_axisangle

View file

@ -8,7 +8,7 @@ int main(int argc,char **argv) {
pw::axisangle_<float> aa = pw::axisangle_<float>();
pw::quaternionf qf = pw::quaternionf::from_axisangle(aa);
// pw::quaternionf qf = pw::quaternionf::from_axisangle(aa);
// std::cout << "aa as quaternion as vector = " << pw::serialize::matrix(qf.as_vector()) << std::endl;

View file

@ -37,7 +37,7 @@ int main(int argc,char **argv) {
vector2f v2;
v2[0] = 1; v2[1] = 3;
vector2f v3(1.f,2.f);
vector2f v3( { 1.f,2.f } );
auto m22_inv = m22.inverse();
auto m22_id = m22_inv * m22;
@ -65,8 +65,11 @@ int main(int argc,char **argv) {
std::cout << "v2_b.norm " << v2_b.norm() << std::endl;
v2_b.normalize();
std::cout << "v2_b.normalized " << v2_b << std::endl;
// v2_b.normalize();
std::cout << "v2_b.normalized " << v2_b.normalized() << std::endl;
std::cout << "v2_b~v3_t " << rad_to_deg(vector2f::angle_between(v2,v3)) << std::endl;

View file

@ -5,22 +5,24 @@
int main(int argc,char **argv) {
pw::quaternion_<float> qf = pw::quaternionf::rotate_90_degree_around_x();
pw::quaternion_<float> qf;
std::cout << "qf = " << pw::serialize::matrix(qf.as_vector()) << std::endl;
std::cout << "qf = " << pw::serialize::matrix(qf) << std::endl;
std::cout << "qf.matrix() = " << pw::serialize::matrix(qf.to_matrix()) << std::endl;
std::cout << "qf.squared_norm() = " << qf.squared_norm() << std::endl;
std::cout << "qf.dot(qf) = " << qf.dot(qf) << std::endl;
std::cout << "qf.conjugate() = " << pw::serialize::matrix(qf.conjugate().as_vector()) << std::endl;
// std::cout << "qf.dot(qf) = " << qf.dot(qf) << std::endl;
std::cout << "qf.conjugate() = " << pw::serialize::matrix(qf.conjugate()) << std::endl;
pw::quaternionf qc = qf.conjugate();
std::cout << "qf.conjugate() (qc) = " << pw::serialize::matrix(qc) << std::endl;
pw::quaternionf qi = qf.inverse();
std::cout << "qf.inverse() (qi) = " << pw::serialize::matrix(qi.as_vector()) << std::endl;
std::cout << "qf.inverse() (qi) = " << pw::serialize::matrix(qi) << std::endl;
// pw::quaternionf qmid = pw::quaternionf::normalized_lerp(qi,qf,0.5f);
pw::quaternionf qmid = pw::quaternionf::normalized_lerp(qi,qf,0.5f);
std::cout << "qmid.dot() (half between qf and qi) = " << pw::rad_to_deg(std::acos(qmid.dot(qf))) << std::endl;
// std::cout << "qmid.dot() (half between qf and qi) = " << pw::rad_to_deg(std::acos(qmid.dot(qf))) << std::endl;

View file

@ -7,20 +7,25 @@
int main(int argc,char **argv) {
pw::vector4_<float> v4;
pw::vector3f v;
v4.fill(1.5);
std::cout << "v4 = " << pw::serialize::matrix(v4) << std::endl;
std::cout << "row_stride() : " << v4.row_stride() << std::endl;
std::cout << "col_stride() : " << v4.col_stride() << std::endl;
std::cout << "rows() : " << v4.rows() << std::endl;
std::cout << "cols() : " << v4.cols() << std::endl;
std::cout << "data() : " << v4.data() << std::endl;
std::cout << "data()[0] : " << v4.data()[0] << std::endl;
std::cout << "at(0,0) : " << v4.at(0,0) << std::endl;
std::cout << "ptr() : " << v4.ptr() << std::endl;
std::cout << "ptr()[0] : " << v4.ptr()[0] << std::endl;
std::cout << "(0,0) : " << v4(0,0) << std::endl;
pw::vector3f v3 = v4.xyz();
auto v3 = v4.xyz();
auto v3_p = v4.project();
auto v3_h = v.homogenous();
// auto v3_lerp = vector4f::lerp()
std::cout << "v3 = " << pw::serialize::matrix(v3) << std::endl;