Add generic affine transform class & unify transform interfaces
This commit is contained in:
parent
325f90d7c8
commit
2b57e3e696
6 changed files with 522 additions and 231 deletions
147
libs/geom/include/psemek/geom/affine_transform.hpp
Normal file
147
libs/geom/include/psemek/geom/affine_transform.hpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/geom/vector.hpp>
|
||||
#include <psemek/geom/point.hpp>
|
||||
#include <psemek/geom/matrix.hpp>
|
||||
#include <psemek/geom/gauss.hpp>
|
||||
|
||||
namespace psemek::geom
|
||||
{
|
||||
|
||||
// Affine transformation from M-dimensional to N-dimensional affine space
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
struct affine_transform
|
||||
{
|
||||
matrix<T, N, M + 1> m;
|
||||
|
||||
static affine_transform zero();
|
||||
|
||||
affine_transform();
|
||||
affine_transform(matrix<T, N, M + 1> const & matrix);
|
||||
affine_transform(matrix<T, N, M> const & linear, vector<T, N> const & translation);
|
||||
affine_transform(affine_transform const &) = default;
|
||||
|
||||
matrix<T, N, M + 1> affine_matrix() const;
|
||||
matrix<T, N, M> linear_matrix() const;
|
||||
vector<T, N> translation_vector() const;
|
||||
matrix<T, N + 1, M + 1> homogeneous_matrix() const;
|
||||
|
||||
vector<T, N> operator()(vector<T, M> const & v) const;
|
||||
point<T, N> operator()(point<T, M> const & p) const;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
affine_transform<T, N, M> affine_transform<T, N, M>::zero()
|
||||
{
|
||||
return affine_transform<T, N, M>{matrix<T, N, M + 1>::zero()};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
affine_transform<T, N, M>::affine_transform()
|
||||
: m{m.zero()}
|
||||
{
|
||||
for (std::size_t i = 0; i < std::min(N, M); ++i)
|
||||
m[i][i] = T{1};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
affine_transform<T, N, M>::affine_transform(matrix<T, N, M + 1> const & matrix)
|
||||
: m{matrix}
|
||||
{}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
affine_transform<T, N, M>::affine_transform(matrix<T, N, M> const & linear, vector<T, N> const & translation)
|
||||
{
|
||||
for (std::size_t r = 0; r < N; ++r)
|
||||
{
|
||||
for (std::size_t c = 0; c < M; ++c)
|
||||
m[r][c] = linear[r][c];
|
||||
m[r][M] = translation[r];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
matrix<T, N, M + 1> affine_transform<T, N, M>::affine_matrix() const
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
matrix<T, N, M> affine_transform<T, N, M>::linear_matrix() const
|
||||
{
|
||||
matrix<T, N, M> result;
|
||||
for (std::size_t r = 0; r < N; ++r)
|
||||
{
|
||||
for (std::size_t c = 0; c < M; ++c)
|
||||
result[r][c] = m[r][c];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
vector<T, N> affine_transform<T, N, M>::translation_vector() const
|
||||
{
|
||||
vector<T, N> result;
|
||||
for (std::size_t r = 0; r < N; ++r)
|
||||
result[r] = m[r][M];
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
matrix<T, N + 1, M + 1> affine_transform<T, N, M>::homogeneous_matrix() const
|
||||
{
|
||||
matrix<T, N + 1, M + 1> result;
|
||||
for (std::size_t r = 0; r < N; ++r)
|
||||
{
|
||||
for (std::size_t c = 0; c <= M; ++c)
|
||||
result[r][c] = m[r][c];
|
||||
}
|
||||
for (std::size_t c = 0; c < M; ++c)
|
||||
result[N][c] = T{0};
|
||||
result[N][M] = T{1};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
vector<T, N> affine_transform<T, N, M>::operator()(vector<T, M> const & v) const
|
||||
{
|
||||
vector<T, N> result = vector<T, N>::zero();
|
||||
for (std::size_t r = 0; r < N; ++r)
|
||||
{
|
||||
for (std::size_t c = 0; c < M; ++c)
|
||||
result[r] += m[r][c] * v[c];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M>
|
||||
point<T, N> affine_transform<T, N, M>::operator()(point<T, M> const & p) const
|
||||
{
|
||||
point<T, N> result = point<T, N>::zero();
|
||||
for (std::size_t r = 0; r < N; ++r)
|
||||
{
|
||||
for (std::size_t c = 0; c < M; ++c)
|
||||
result[r] += m[r][c] * p[c];
|
||||
result[r] += m[r][M];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N, std::size_t M, std::size_t K>
|
||||
affine_transform<T, N, K> operator * (affine_transform<T, N, M> const & t1, affine_transform<T, M, K> const & t2)
|
||||
{
|
||||
auto const t1_lin = t1.linear_matrix();
|
||||
return {t1_lin * t2.linear_matrix(), t1_lin * t2.translation_vector() + t1.translation_vector()};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
std::optional<affine_transform<T, N, N>> inverse(affine_transform<T, N, N> const & t)
|
||||
{
|
||||
auto lin_inv = inverse(t.linear_matrix());
|
||||
if (!lin_inv)
|
||||
return std::nullopt;
|
||||
|
||||
return affine_transform<T, N, N>{lin_inv, - lin_inv * t.translation()};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,59 +1,108 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/geom/vector.hpp>
|
||||
#include <psemek/geom/point.hpp>
|
||||
#include <psemek/geom/matrix.hpp>
|
||||
#include <psemek/geom/affine_transform.hpp>
|
||||
|
||||
#include <psemek/util/assert.hpp>
|
||||
|
||||
namespace psemek::geom
|
||||
{
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
template <typename T, std::size_t N>
|
||||
struct swap
|
||||
{
|
||||
using vector_type = geom::vector<T, D>;
|
||||
using point_type = geom::point<T, D>;
|
||||
using matrix_type = geom::matrix<T, D, D>;
|
||||
std::size_t i, j;
|
||||
|
||||
swap(std::size_t i, std::size_t j);
|
||||
swap(swap const &) = default;
|
||||
|
||||
vector_type operator()(vector_type v) const;
|
||||
matrix<T, N, N + 1> affine_matrix() const;
|
||||
matrix<T, N, N> linear_matrix() const;
|
||||
vector<T, N> translation_vector() const;
|
||||
matrix<T, N + 1, N + 1> homogeneous_matrix() const;
|
||||
|
||||
matrix_type matrix() const;
|
||||
affine_transform<T, N, N> transform() const;
|
||||
|
||||
swap inverse() const;
|
||||
vector<T, N> operator()(vector<T, N> v) const;
|
||||
point<T, N> operator()(point<T, N> p) const;
|
||||
|
||||
private:
|
||||
std::size_t i_, j_;
|
||||
template <typename Matrix>
|
||||
void fill_matrix(Matrix & m) const;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
swap<T, D>::swap(std::size_t i, std::size_t j)
|
||||
: i_(i)
|
||||
, j_(j)
|
||||
{}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> swap<T, D>::operator()(vector_type v) const
|
||||
template <typename T, std::size_t N>
|
||||
swap<T, N>::swap(std::size_t i, std::size_t j)
|
||||
: i{i}
|
||||
, j{j}
|
||||
{
|
||||
std::swap(v[i_], v[j_]);
|
||||
assert(i < N);
|
||||
assert(j < N);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> swap<T, N>::operator()(vector<T, N> v) const
|
||||
{
|
||||
std::swap(v[i], v[j]);
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
matrix<T, D, D> swap<T, D>::matrix() const
|
||||
template <typename T, std::size_t N>
|
||||
point<T, N> swap<T, N>::operator()(point<T, N> p) const
|
||||
{
|
||||
matrix_type m = matrix_type::identity();
|
||||
m[i_][i_] = 0;
|
||||
m[j_][j_] = 0;
|
||||
m[i_][j_] = 1;
|
||||
m[j_][i_] = 1;
|
||||
return m;
|
||||
std::swap(p[i], p[j]);
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
swap<T, D> swap<T, D>::inverse() const
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N + 1> swap<T, N>::affine_matrix() const
|
||||
{
|
||||
return *this;
|
||||
auto result = matrix<T, N, N + 1>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N> swap<T, N>::linear_matrix() const
|
||||
{
|
||||
auto result = matrix<T, N, N>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> swap<T, N>::translation_vector() const
|
||||
{
|
||||
return vector<T, N>::zero();
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N + 1, N + 1> swap<T, N>::homogeneous_matrix() const
|
||||
{
|
||||
auto result = matrix<T, N + 1, N + 1>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
affine_transform<T, N, N> swap<T, N>::transform() const
|
||||
{
|
||||
return {affine_matrix()};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
template <typename Matrix>
|
||||
void swap<T, N>::fill_matrix(Matrix & m) const
|
||||
{
|
||||
m[i][i] = T{0};
|
||||
m[j][j] = T{0};
|
||||
m[i][j] = T{1};
|
||||
m[j][i] = T{1};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
swap<T, N> inverse(swap<T, N> const & s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,168 +1,224 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/geom/vector.hpp>
|
||||
#include <psemek/geom/point.hpp>
|
||||
#include <psemek/geom/matrix.hpp>
|
||||
#include <psemek/geom/homogeneous.hpp>
|
||||
#include <psemek/geom/affine_transform.hpp>
|
||||
|
||||
#include <psemek/util/assert.hpp>
|
||||
|
||||
namespace psemek::geom
|
||||
{
|
||||
|
||||
// Rotation in oriented plane (i,j)
|
||||
template <typename T, std::size_t D>
|
||||
template <typename T, std::size_t N>
|
||||
struct plane_rotation
|
||||
{
|
||||
using scalar_type = T;
|
||||
using vector_type = geom::vector<T, D>;
|
||||
using point_type = geom::point<T, D>;
|
||||
using matrix_type = geom::matrix<T, D, D>;
|
||||
std::size_t i, j;
|
||||
T angle;
|
||||
|
||||
plane_rotation(std::size_t i, std::size_t j, T angle = T(0));
|
||||
plane_rotation();
|
||||
plane_rotation(std::size_t i, std::size_t j, T angle);
|
||||
plane_rotation(plane_rotation const &) = default;
|
||||
|
||||
scalar_type angle() const;
|
||||
scalar_type angle(scalar_type a);
|
||||
matrix<T, N, N + 1> affine_matrix() const;
|
||||
matrix<T, N, N> linear_matrix() const;
|
||||
vector<T, N> translation_vector() const;
|
||||
matrix<T, N + 1, N + 1> homogeneous_matrix() const;
|
||||
|
||||
vector_type operator()(vector_type v) const;
|
||||
affine_transform<T, N, N> transform() const;
|
||||
|
||||
matrix_type matrix() const;
|
||||
|
||||
plane_rotation inverse() const;
|
||||
vector<T, N> operator()(vector<T, N> const & v) const;
|
||||
point<T, N> operator()(point<T, N> const & p) const;
|
||||
|
||||
private:
|
||||
std::size_t const i_;
|
||||
std::size_t const j_;
|
||||
T angle_;
|
||||
template <typename Matrix>
|
||||
void fill_matrix(Matrix & m) const;
|
||||
};
|
||||
|
||||
// 3D-rotation around an axis
|
||||
// 3N-rotation around an axis
|
||||
template <typename T>
|
||||
struct axis_rotation
|
||||
{
|
||||
using scalar_type = T;
|
||||
using vector_type = geom::vector<T, 3>;
|
||||
using point_type = geom::point<T, 3>;
|
||||
using matrix_type = geom::matrix<T, 3, 3>;
|
||||
vector<T, 3> axis;
|
||||
T angle;
|
||||
|
||||
axis_rotation();
|
||||
axis_rotation(vector_type axis, scalar_type angle);
|
||||
axis_rotation(vector<T, 3> const & axis, T angle);
|
||||
axis_rotation(axis_rotation const &) = default;
|
||||
|
||||
vector_type axis() const;
|
||||
vector_type axis(vector_type a);
|
||||
matrix<T, 3, 4> affine_matrix() const;
|
||||
matrix<T, 3, 3> linear_matrix() const;
|
||||
vector<T, 3> translation_vector() const;
|
||||
matrix<T, 4, 4> homogeneous_matrix() const;
|
||||
|
||||
scalar_type angle() const;
|
||||
scalar_type angle(scalar_type a);
|
||||
affine_transform<T, 3, 3> transform() const;
|
||||
|
||||
vector_type operator()(vector_type v) const;
|
||||
|
||||
matrix_type matrix() const;
|
||||
|
||||
axis_rotation inverse() const;
|
||||
vector<T, 3> operator()(vector<T, 3> const & v) const;
|
||||
point<T, 3> operator()(point<T, 3> const & p) const;
|
||||
|
||||
private:
|
||||
vector_type axis_;
|
||||
scalar_type angle_;
|
||||
template <typename Matrix>
|
||||
void fill_matrix(Matrix & m) const;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
plane_rotation<T, D>::plane_rotation(std::size_t i, std::size_t j, T angle)
|
||||
: i_(i), j_(j), angle_(angle)
|
||||
{}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
T plane_rotation<T, D>::angle() const
|
||||
template <typename T, std::size_t N>
|
||||
plane_rotation<T, N>::plane_rotation()
|
||||
: i{0}
|
||||
, j{1}
|
||||
, angle{0}
|
||||
{
|
||||
return angle_;
|
||||
assert(i < N);
|
||||
assert(j < N);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
T plane_rotation<T, D>::angle(T a)
|
||||
template <typename T, std::size_t N>
|
||||
plane_rotation<T, N>::plane_rotation(std::size_t i, std::size_t j, T angle)
|
||||
: i{i}
|
||||
, j{j}
|
||||
, angle{angle}
|
||||
{
|
||||
T t = angle_;
|
||||
angle_ = a;
|
||||
return t;
|
||||
assert(i < N);
|
||||
assert(j < N);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> plane_rotation<T, D>::operator()(vector_type v) const
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N + 1> plane_rotation<T, N>::affine_matrix() const
|
||||
{
|
||||
T vi = v[i_] * std::cos(angle_) - v[j_] * std::sin(angle_);
|
||||
T vj = v[i_] * std::sin(angle_) + v[j_] * std::cos(angle_);
|
||||
v[i_] = vi;
|
||||
v[j_] = vj;
|
||||
return v;
|
||||
auto result = matrix<T, N, N + 1>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
matrix<T, D, D> plane_rotation<T, D>::matrix() const
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N> plane_rotation<T, N>::linear_matrix() const
|
||||
{
|
||||
matrix_type m = matrix_type::identity();
|
||||
m[i_][i_] = std::cos(angle_);
|
||||
m[i_][j_] = -std::sin(angle_);
|
||||
m[j_][i_] = std::sin(angle_);
|
||||
m[j_][j_] = std::cos(angle_);
|
||||
return m;
|
||||
auto result = matrix<T, N, N>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
plane_rotation<T, D> plane_rotation<T, D>::inverse() const
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> plane_rotation<T, N>::translation_vector() const
|
||||
{
|
||||
return {i_, j_, -angle_};
|
||||
return vector<T, N>::zero();
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N + 1, N + 1> plane_rotation<T, N>::homogeneous_matrix() const
|
||||
{
|
||||
auto result = matrix<T, N + 1, N + 1>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
affine_transform<T, N, N> plane_rotation<T, N>::transform() const
|
||||
{
|
||||
return {affine_matrix()};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> plane_rotation<T, N>::operator()(vector<T, N> const & v) const
|
||||
{
|
||||
auto result = v;
|
||||
result[i] = v[i] * std::cos(angle) - v[j] * std::sin(angle);
|
||||
result[j] = v[i] * std::sin(angle) + v[j] * std::cos(angle);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
point<T, N> plane_rotation<T, N>::operator()(point<T, N> const & p) const
|
||||
{
|
||||
auto result = p;
|
||||
result[i] = p[i] * std::cos(angle) - p[j] * std::sin(angle);
|
||||
result[j] = p[i] * std::sin(angle) + p[j] * std::cos(angle);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
template <typename Matrix>
|
||||
void plane_rotation<T, N>::fill_matrix(Matrix & m) const
|
||||
{
|
||||
m[i][i] = std::cos(angle);
|
||||
m[i][j] = -std::sin(angle);
|
||||
m[j][i] = std::sin(angle);
|
||||
m[j][j] = std::cos(angle);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
plane_rotation<T, N> inverse(plane_rotation<T, N> const & r)
|
||||
{
|
||||
return {r.j, r.i, r.angle};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
axis_rotation<T>::axis_rotation()
|
||||
: axis_rotation(vector_type{T(0), T(0), T(1)}, T(0))
|
||||
: axis{T{0}, T{0}, T{1}}
|
||||
, angle{T{0}}
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
axis_rotation<T>::axis_rotation(vector_type axis, scalar_type angle)
|
||||
: axis_(axis)
|
||||
, angle_(angle)
|
||||
axis_rotation<T>::axis_rotation(vector<T, 3> const & axis, T angle)
|
||||
: axis{axis}
|
||||
, angle{angle}
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
vector<T, 3> axis_rotation<T>::axis() const
|
||||
matrix<T, 3, 4> axis_rotation<T>::affine_matrix() const
|
||||
{
|
||||
return axis_;
|
||||
auto result = matrix<T, 3, 4>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
vector<T, 3> axis_rotation<T>::axis(vector_type a)
|
||||
matrix<T, 3, 3> axis_rotation<T>::linear_matrix() const
|
||||
{
|
||||
auto t = axis_;
|
||||
axis_ = a;
|
||||
return t;
|
||||
auto result = matrix<T, 3, 3>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T axis_rotation<T>::angle() const
|
||||
vector<T, 3> axis_rotation<T>::translation_vector() const
|
||||
{
|
||||
return angle_;
|
||||
return vector<T, 3>::zero();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T axis_rotation<T>::angle(scalar_type a)
|
||||
matrix<T, 4, 4> axis_rotation<T>::homogeneous_matrix() const
|
||||
{
|
||||
auto t = angle_;
|
||||
angle_ = a;
|
||||
return t;
|
||||
auto result = matrix<T, 4, 4>::identity();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
vector<T, 3> axis_rotation<T>::operator()(vector_type v) const
|
||||
affine_transform<T, 3, 3> axis_rotation<T>::transform() const
|
||||
{
|
||||
return matrix() * v;
|
||||
return {affine_matrix()};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
matrix<T, 3, 3> axis_rotation<T>::matrix() const
|
||||
vector<T, 3> axis_rotation<T>::operator()(vector<T, 3> const & v) const
|
||||
{
|
||||
matrix_type m = matrix_type::identity();
|
||||
T c = std::cos(angle_);
|
||||
T s = std::sin(angle_);
|
||||
T x = axis_[0];
|
||||
T y = axis_[1];
|
||||
T z = axis_[2];
|
||||
return linear_matrix() * v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
point<T, 3> axis_rotation<T>::operator()(point<T, 3> const & p) const
|
||||
{
|
||||
auto const o = geom::point<T, 3>::zero();
|
||||
return linear_matrix() * (p - o) + o;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Matrix>
|
||||
void axis_rotation<T>::fill_matrix(Matrix & m) const
|
||||
{
|
||||
T const c = std::cos(angle);
|
||||
T const s = std::sin(angle);
|
||||
T const x = axis[0];
|
||||
T const y = axis[1];
|
||||
T const z = axis[2];
|
||||
m[0][0] = c + x * x * (1 - c);
|
||||
m[0][1] = x * y * (1 - c) - z * s;
|
||||
m[0][2] = x * z * (1 - c) + y * s;
|
||||
|
|
@ -172,13 +228,12 @@ namespace psemek::geom
|
|||
m[2][0] = z * x * (1 - c) - y * s;
|
||||
m[2][1] = z * y * (1 - c) + x * s;
|
||||
m[2][2] = c + z * z * (1 - c);
|
||||
return m;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
axis_rotation<T> axis_rotation<T>::inverse() const
|
||||
axis_rotation<T> inverse(axis_rotation<T> const & r)
|
||||
{
|
||||
return {axis_, -angle_};
|
||||
return {r.axis, -r.angle};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,93 +1,125 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/geom/vector.hpp>
|
||||
#include <psemek/geom/point.hpp>
|
||||
#include <psemek/geom/matrix.hpp>
|
||||
#include <psemek/geom/affine_transform.hpp>
|
||||
|
||||
namespace psemek::geom
|
||||
{
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
template <typename T, std::size_t N>
|
||||
struct scale
|
||||
{
|
||||
using vector_type = geom::vector<T, D>;
|
||||
using point_type = geom::point<T, D>;
|
||||
using matrix_type = geom::matrix<T, D, D>;
|
||||
vector<T, N> s;
|
||||
|
||||
scale();
|
||||
scale(T v);
|
||||
scale(vector_type v);
|
||||
scale(T s);
|
||||
scale(vector<T, N> const & s);
|
||||
scale(scale const &) = default;
|
||||
|
||||
vector_type vector() const;
|
||||
vector_type vector(vector_type v);
|
||||
matrix<T, N, N + 1> affine_matrix() const;
|
||||
matrix<T, N, N> linear_matrix() const;
|
||||
vector<T, N> translation_vector() const;
|
||||
matrix<T, N + 1, N + 1> homogeneous_matrix() const;
|
||||
|
||||
vector_type operator()(vector_type v) const;
|
||||
affine_transform<T, N, N> transform() const;
|
||||
|
||||
matrix_type matrix() const;
|
||||
|
||||
scale inverse() const;
|
||||
vector<T, N> operator()(vector<T, N> v) const;
|
||||
point<T, N> operator()(point<T, N> p) const;
|
||||
|
||||
private:
|
||||
vector_type v_;
|
||||
template <typename Matrix>
|
||||
void fill_matrix(Matrix & m) const;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
scale<T, D>::scale()
|
||||
template <typename T, std::size_t N>
|
||||
scale<T, N>::scale()
|
||||
{
|
||||
for (std::size_t i = 0; i < D; ++i)
|
||||
v_[i] = T(1);
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
s[i] = T{1};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
scale<T, D>::scale(T v)
|
||||
template <typename T, std::size_t N>
|
||||
scale<T, N>::scale(T s)
|
||||
{
|
||||
for (std::size_t i = 0; i < D; ++i)
|
||||
v_[i] = v;
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
this->s[i] = s;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
scale<T, D>::scale(vector_type v)
|
||||
: v_(v)
|
||||
template <typename T, std::size_t N>
|
||||
scale<T, N>::scale(vector<T, N> const & s)
|
||||
: s{s}
|
||||
{}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> scale<T, D>::vector() const
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N + 1> scale<T, N>::affine_matrix() const
|
||||
{
|
||||
return v_;
|
||||
auto result = matrix<T, N, N + 1>::zero();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> scale<T, D>::vector(vector_type v)
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N> scale<T, N>::linear_matrix() const
|
||||
{
|
||||
auto t = v_;
|
||||
v_ = v;
|
||||
return t;
|
||||
auto result = matrix<T, N, N>::zero();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> scale<T, D>::operator()(vector_type v) const
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> scale<T, N>::translation_vector() const
|
||||
{
|
||||
for (std::size_t i = 0; i < D; ++i)
|
||||
v[i] *= v_[i];
|
||||
return vector<T, N>::zero();
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N + 1, N + 1> scale<T, N>::homogeneous_matrix() const
|
||||
{
|
||||
auto result = matrix<T, N + 1, N + 1>::zero();
|
||||
fill_matrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
affine_transform<T, N, N> scale<T, N>::transform() const
|
||||
{
|
||||
return {affine_matrix()};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> scale<T, N>::operator()(vector<T, N> v) const
|
||||
{
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
v[i] *= s[i];
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
matrix<T, D, D> scale<T, D>::matrix() const
|
||||
template <typename T, std::size_t N>
|
||||
point<T, N> scale<T, N>::operator()(point<T, N> p) const
|
||||
{
|
||||
matrix_type m = matrix_type::identity();
|
||||
for (std::size_t i = 0; i < D; ++i)
|
||||
m[i][i] = v_[i];
|
||||
return m;
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
p[i] *= s[i];
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
scale<T, D> scale<T, D>::inverse() const
|
||||
template <typename T, std::size_t N>
|
||||
template <typename Matrix>
|
||||
void scale<T, N>::fill_matrix(Matrix & m) const
|
||||
{
|
||||
vector_type v;
|
||||
for (std::size_t i = 0; i < D; ++i)
|
||||
v[i] = T(1) / v_[i];
|
||||
return {v};
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
m[i][i] = s[i];
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
std::optional<scale<T, N>> inverse(scale<T, N> const & s)
|
||||
{
|
||||
vector<T, N> result;
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
if (s.s[i] == T{0})
|
||||
return std::nullopt;
|
||||
result[i] = T{1} / s.s[i];
|
||||
}
|
||||
return scale<T, N>{result};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,85 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/geom/vector.hpp>
|
||||
#include <psemek/geom/point.hpp>
|
||||
#include <psemek/geom/matrix.hpp>
|
||||
#include <psemek/geom/affine_transform.hpp>
|
||||
|
||||
namespace psemek::geom
|
||||
{
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
template <typename T, std::size_t N>
|
||||
struct translation
|
||||
{
|
||||
using vector_type = geom::vector<T, D>;
|
||||
using point_type = geom::point<T, D>;
|
||||
using homogeneous_matrix_type = geom::matrix<T, D + 1, D + 1>;
|
||||
vector<T, N> v;
|
||||
|
||||
translation();
|
||||
translation(vector_type v);
|
||||
translation(vector<T, N> const & v);
|
||||
translation(translation const &) = default;
|
||||
|
||||
vector_type vector() const;
|
||||
vector_type vector(vector_type v);
|
||||
matrix<T, N, N + 1> affine_matrix() const;
|
||||
matrix<T, N, N> linear_matrix() const;
|
||||
vector<T, N> translation_vector() const;
|
||||
matrix<T, N + 1, N + 1> homogeneous_matrix() const;
|
||||
|
||||
vector_type operator()(vector_type v) const;
|
||||
point_type operator()(point_type p) const;
|
||||
affine_transform<T, N, N> transform() const;
|
||||
|
||||
homogeneous_matrix_type homogeneous_matrix() const;
|
||||
|
||||
translation inverse() const;
|
||||
|
||||
private:
|
||||
vector_type v_;
|
||||
vector<T, N> operator()(vector<T, N> const & v) const;
|
||||
point<T, N> operator()(point<T, N> const & p) const;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
translation<T, D>::translation()
|
||||
: translation(vector_type::zero())
|
||||
template <typename T, std::size_t N>
|
||||
translation<T, N>::translation()
|
||||
: v{vector<T, N>::zero()}
|
||||
{}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
translation<T, D>::translation(vector_type v)
|
||||
: v_(v)
|
||||
template <typename T, std::size_t N>
|
||||
translation<T, N>::translation(vector<T, N> const & v)
|
||||
: v{v}
|
||||
{}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> translation<T, D>::vector() const
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N + 1> translation<T, N>::affine_matrix() const
|
||||
{
|
||||
return v_;
|
||||
auto result = matrix<T, N, N + 1>::identity();
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
result[i][N] = v[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> translation<T, D>::vector(vector_type v)
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N, N> translation<T, N>::linear_matrix() const
|
||||
{
|
||||
auto t = v_;
|
||||
v_ = v;
|
||||
return t;
|
||||
return matrix<T, N, N>::identity();
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
vector<T, D> translation<T, D>::operator()(vector_type v) const
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> translation<T, N>::translation_vector() const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
point<T, D> translation<T, D>::operator()(point_type p) const
|
||||
template <typename T, std::size_t N>
|
||||
matrix<T, N + 1, N + 1> translation<T, N>::homogeneous_matrix() const
|
||||
{
|
||||
return p + v_;
|
||||
auto result = matrix<T, N + 1, N + 1>::identity();
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
result[i][N] = v[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
matrix<T, D + 1, D + 1> translation<T, D>::homogeneous_matrix() const
|
||||
template <typename T, std::size_t N>
|
||||
affine_transform<T, N, N> translation<T, N>::transform() const
|
||||
{
|
||||
homogeneous_matrix_type m = homogeneous_matrix_type::identity();
|
||||
for (std::size_t i = 0; i < D; ++i)
|
||||
m[i][D] = v_[i];
|
||||
return m;
|
||||
return {affine_matrix()};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t D>
|
||||
translation<T, D> translation<T, D>::inverse() const
|
||||
template <typename T, std::size_t N>
|
||||
vector<T, N> translation<T, N>::operator()(vector<T, N> const & v) const
|
||||
{
|
||||
return {-v_};
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
point<T, N> translation<T, N>::operator()(point<T, N> const & p) const
|
||||
{
|
||||
return p + v;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
translation<T, N> inverse(translation<T, N> const & t)
|
||||
{
|
||||
return {-t.v};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include <psemek/geom/rotation.hpp>
|
||||
#include <psemek/geom/permutation.hpp>
|
||||
#include <psemek/geom/scale.hpp>
|
||||
#include <psemek/geom/homogeneous.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
|
@ -109,14 +108,16 @@ namespace psemek::geom
|
|||
|
||||
matrix<float, 4, 4> spherical_camera::view() const
|
||||
{
|
||||
return
|
||||
translation<float, 3>({0.f, 0.f, -distance}).homogeneous_matrix()
|
||||
* homogeneous(swap<float, 3>(1, 2).matrix())
|
||||
* homogeneous(scale<float, 3>({1.f, -1.f, 1.f}).matrix())
|
||||
* homogeneous(plane_rotation<float, 3>(1, 2, elevation_angle).matrix())
|
||||
* homogeneous(plane_rotation<float, 3>(1, 0, azimuthal_angle).matrix())
|
||||
* translation<float, 3>({ -target[0], -target[1], -target[2] }).homogeneous_matrix()
|
||||
auto tr =
|
||||
translation<float, 3>({0.f, 0.f, -distance}).transform()
|
||||
* swap<float, 3>(1, 2).transform()
|
||||
* scale<float, 3>({1.f, -1.f, 1.f}).transform()
|
||||
* plane_rotation<float, 3>(1, 2, elevation_angle).transform()
|
||||
* plane_rotation<float, 3>(1, 0, azimuthal_angle).transform()
|
||||
* translation<float, 3>({ -target[0], -target[1], -target[2] }).transform()
|
||||
;
|
||||
|
||||
return tr.homogeneous_matrix();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue