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
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/geom/vector.hpp>
|
#include <psemek/geom/affine_transform.hpp>
|
||||||
#include <psemek/geom/point.hpp>
|
|
||||||
#include <psemek/geom/matrix.hpp>
|
#include <psemek/util/assert.hpp>
|
||||||
|
|
||||||
namespace psemek::geom
|
namespace psemek::geom
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
struct swap
|
struct swap
|
||||||
{
|
{
|
||||||
using vector_type = geom::vector<T, D>;
|
std::size_t i, j;
|
||||||
using point_type = geom::point<T, D>;
|
|
||||||
using matrix_type = geom::matrix<T, D, D>;
|
|
||||||
|
|
||||||
swap(std::size_t i, std::size_t 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:
|
private:
|
||||||
std::size_t i_, j_;
|
template <typename Matrix>
|
||||||
|
void fill_matrix(Matrix & m) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
swap<T, D>::swap(std::size_t i, std::size_t j)
|
swap<T, N>::swap(std::size_t i, std::size_t j)
|
||||||
: i_(i)
|
: i{i}
|
||||||
, j_(j)
|
, j{j}
|
||||||
{}
|
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
|
||||||
vector<T, D> swap<T, D>::operator()(vector_type v) const
|
|
||||||
{
|
{
|
||||||
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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
matrix<T, D, D> swap<T, D>::matrix() const
|
point<T, N> swap<T, N>::operator()(point<T, N> p) const
|
||||||
{
|
{
|
||||||
matrix_type m = matrix_type::identity();
|
std::swap(p[i], p[j]);
|
||||||
m[i_][i_] = 0;
|
return p;
|
||||||
m[j_][j_] = 0;
|
|
||||||
m[i_][j_] = 1;
|
|
||||||
m[j_][i_] = 1;
|
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
swap<T, D> swap<T, D>::inverse() const
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/geom/vector.hpp>
|
#include <psemek/geom/affine_transform.hpp>
|
||||||
#include <psemek/geom/point.hpp>
|
|
||||||
#include <psemek/geom/matrix.hpp>
|
#include <psemek/util/assert.hpp>
|
||||||
#include <psemek/geom/homogeneous.hpp>
|
|
||||||
|
|
||||||
namespace psemek::geom
|
namespace psemek::geom
|
||||||
{
|
{
|
||||||
|
|
||||||
// Rotation in oriented plane (i,j)
|
// Rotation in oriented plane (i,j)
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
struct plane_rotation
|
struct plane_rotation
|
||||||
{
|
{
|
||||||
using scalar_type = T;
|
std::size_t i, j;
|
||||||
using vector_type = geom::vector<T, D>;
|
T angle;
|
||||||
using point_type = geom::point<T, D>;
|
|
||||||
using matrix_type = geom::matrix<T, D, D>;
|
|
||||||
|
|
||||||
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;
|
matrix<T, N, N + 1> affine_matrix() const;
|
||||||
scalar_type angle(scalar_type a);
|
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;
|
vector<T, N> operator()(vector<T, N> const & v) const;
|
||||||
|
point<T, N> operator()(point<T, N> const & p) const;
|
||||||
plane_rotation inverse() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t const i_;
|
template <typename Matrix>
|
||||||
std::size_t const j_;
|
void fill_matrix(Matrix & m) const;
|
||||||
T angle_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 3D-rotation around an axis
|
// 3N-rotation around an axis
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct axis_rotation
|
struct axis_rotation
|
||||||
{
|
{
|
||||||
using scalar_type = T;
|
vector<T, 3> axis;
|
||||||
using vector_type = geom::vector<T, 3>;
|
T angle;
|
||||||
using point_type = geom::point<T, 3>;
|
|
||||||
using matrix_type = geom::matrix<T, 3, 3>;
|
|
||||||
|
|
||||||
axis_rotation();
|
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;
|
matrix<T, 3, 4> affine_matrix() const;
|
||||||
vector_type axis(vector_type a);
|
matrix<T, 3, 3> linear_matrix() const;
|
||||||
|
vector<T, 3> translation_vector() const;
|
||||||
|
matrix<T, 4, 4> homogeneous_matrix() const;
|
||||||
|
|
||||||
scalar_type angle() const;
|
affine_transform<T, 3, 3> transform() const;
|
||||||
scalar_type angle(scalar_type a);
|
|
||||||
|
|
||||||
vector_type operator()(vector_type v) const;
|
vector<T, 3> operator()(vector<T, 3> const & v) const;
|
||||||
|
point<T, 3> operator()(point<T, 3> const & p) const;
|
||||||
matrix_type matrix() const;
|
|
||||||
|
|
||||||
axis_rotation inverse() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector_type axis_;
|
template <typename Matrix>
|
||||||
scalar_type angle_;
|
void fill_matrix(Matrix & m) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
plane_rotation<T, D>::plane_rotation(std::size_t i, std::size_t j, T angle)
|
plane_rotation<T, N>::plane_rotation()
|
||||||
: i_(i), j_(j), angle_(angle)
|
: i{0}
|
||||||
{}
|
, j{1}
|
||||||
|
, angle{0}
|
||||||
template <typename T, std::size_t D>
|
|
||||||
T plane_rotation<T, D>::angle() const
|
|
||||||
{
|
{
|
||||||
return angle_;
|
assert(i < N);
|
||||||
|
assert(j < N);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
T plane_rotation<T, D>::angle(T a)
|
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_;
|
assert(i < N);
|
||||||
angle_ = a;
|
assert(j < N);
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
vector<T, D> plane_rotation<T, D>::operator()(vector_type v) const
|
matrix<T, N, N + 1> plane_rotation<T, N>::affine_matrix() const
|
||||||
{
|
{
|
||||||
T vi = v[i_] * std::cos(angle_) - v[j_] * std::sin(angle_);
|
auto result = matrix<T, N, N + 1>::identity();
|
||||||
T vj = v[i_] * std::sin(angle_) + v[j_] * std::cos(angle_);
|
fill_matrix(result);
|
||||||
v[i_] = vi;
|
return result;
|
||||||
v[j_] = vj;
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
matrix<T, D, D> plane_rotation<T, D>::matrix() const
|
matrix<T, N, N> plane_rotation<T, N>::linear_matrix() const
|
||||||
{
|
{
|
||||||
matrix_type m = matrix_type::identity();
|
auto result = matrix<T, N, N>::identity();
|
||||||
m[i_][i_] = std::cos(angle_);
|
fill_matrix(result);
|
||||||
m[i_][j_] = -std::sin(angle_);
|
return result;
|
||||||
m[j_][i_] = std::sin(angle_);
|
|
||||||
m[j_][j_] = std::cos(angle_);
|
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
plane_rotation<T, D> plane_rotation<T, D>::inverse() const
|
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>
|
template <typename T>
|
||||||
axis_rotation<T>::axis_rotation()
|
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>
|
template <typename T>
|
||||||
axis_rotation<T>::axis_rotation(vector_type axis, scalar_type angle)
|
axis_rotation<T>::axis_rotation(vector<T, 3> const & axis, T angle)
|
||||||
: axis_(axis)
|
: axis{axis}
|
||||||
, angle_(angle)
|
, angle{angle}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <typename T>
|
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>
|
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_;
|
auto result = matrix<T, 3, 3>::identity();
|
||||||
axis_ = a;
|
fill_matrix(result);
|
||||||
return t;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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>
|
template <typename T>
|
||||||
T axis_rotation<T>::angle(scalar_type a)
|
matrix<T, 4, 4> axis_rotation<T>::homogeneous_matrix() const
|
||||||
{
|
{
|
||||||
auto t = angle_;
|
auto result = matrix<T, 4, 4>::identity();
|
||||||
angle_ = a;
|
fill_matrix(result);
|
||||||
return t;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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>
|
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();
|
return linear_matrix() * v;
|
||||||
T c = std::cos(angle_);
|
}
|
||||||
T s = std::sin(angle_);
|
|
||||||
T x = axis_[0];
|
template <typename T>
|
||||||
T y = axis_[1];
|
point<T, 3> axis_rotation<T>::operator()(point<T, 3> const & p) const
|
||||||
T z = axis_[2];
|
{
|
||||||
|
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][0] = c + x * x * (1 - c);
|
||||||
m[0][1] = x * y * (1 - c) - z * s;
|
m[0][1] = x * y * (1 - c) - z * s;
|
||||||
m[0][2] = x * z * (1 - c) + y * 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][0] = z * x * (1 - c) - y * s;
|
||||||
m[2][1] = z * y * (1 - c) + x * s;
|
m[2][1] = z * y * (1 - c) + x * s;
|
||||||
m[2][2] = c + z * z * (1 - c);
|
m[2][2] = c + z * z * (1 - c);
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/geom/vector.hpp>
|
#include <psemek/geom/affine_transform.hpp>
|
||||||
#include <psemek/geom/point.hpp>
|
|
||||||
#include <psemek/geom/matrix.hpp>
|
|
||||||
|
|
||||||
namespace psemek::geom
|
namespace psemek::geom
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
struct scale
|
struct scale
|
||||||
{
|
{
|
||||||
using vector_type = geom::vector<T, D>;
|
vector<T, N> s;
|
||||||
using point_type = geom::point<T, D>;
|
|
||||||
using matrix_type = geom::matrix<T, D, D>;
|
|
||||||
|
|
||||||
scale();
|
scale();
|
||||||
scale(T v);
|
scale(T s);
|
||||||
scale(vector_type v);
|
scale(vector<T, N> const & s);
|
||||||
|
scale(scale const &) = default;
|
||||||
|
|
||||||
vector_type vector() const;
|
matrix<T, N, N + 1> affine_matrix() const;
|
||||||
vector_type vector(vector_type v);
|
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;
|
vector<T, N> operator()(vector<T, N> v) const;
|
||||||
|
point<T, N> operator()(point<T, N> p) const;
|
||||||
scale inverse() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector_type v_;
|
template <typename Matrix>
|
||||||
|
void fill_matrix(Matrix & m) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
scale<T, D>::scale()
|
scale<T, N>::scale()
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < D; ++i)
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
v_[i] = T(1);
|
s[i] = T{1};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
scale<T, D>::scale(T v)
|
scale<T, N>::scale(T s)
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < D; ++i)
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
v_[i] = v;
|
this->s[i] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
scale<T, D>::scale(vector_type v)
|
scale<T, N>::scale(vector<T, N> const & s)
|
||||||
: v_(v)
|
: s{s}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
vector<T, D> scale<T, D>::vector() const
|
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>
|
template <typename T, std::size_t N>
|
||||||
vector<T, D> scale<T, D>::vector(vector_type v)
|
matrix<T, N, N> scale<T, N>::linear_matrix() const
|
||||||
{
|
{
|
||||||
auto t = v_;
|
auto result = matrix<T, N, N>::zero();
|
||||||
v_ = v;
|
fill_matrix(result);
|
||||||
return t;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
vector<T, D> scale<T, D>::operator()(vector_type v) const
|
vector<T, N> scale<T, N>::translation_vector() const
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < D; ++i)
|
return vector<T, N>::zero();
|
||||||
v[i] *= v_[i];
|
}
|
||||||
|
|
||||||
|
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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
matrix<T, D, D> scale<T, D>::matrix() const
|
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 < N; ++i)
|
||||||
for (std::size_t i = 0; i < D; ++i)
|
p[i] *= s[i];
|
||||||
m[i][i] = v_[i];
|
return p;
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
scale<T, D> scale<T, D>::inverse() const
|
template <typename Matrix>
|
||||||
|
void scale<T, N>::fill_matrix(Matrix & m) const
|
||||||
{
|
{
|
||||||
vector_type v;
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
for (std::size_t i = 0; i < D; ++i)
|
m[i][i] = s[i];
|
||||||
v[i] = T(1) / v_[i];
|
}
|
||||||
return {v};
|
|
||||||
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/geom/vector.hpp>
|
#include <psemek/geom/affine_transform.hpp>
|
||||||
#include <psemek/geom/point.hpp>
|
|
||||||
#include <psemek/geom/matrix.hpp>
|
|
||||||
|
|
||||||
namespace psemek::geom
|
namespace psemek::geom
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
struct translation
|
struct translation
|
||||||
{
|
{
|
||||||
using vector_type = geom::vector<T, D>;
|
vector<T, N> v;
|
||||||
using point_type = geom::point<T, D>;
|
|
||||||
using homogeneous_matrix_type = geom::matrix<T, D + 1, D + 1>;
|
|
||||||
|
|
||||||
translation();
|
translation();
|
||||||
translation(vector_type v);
|
translation(vector<T, N> const & v);
|
||||||
|
translation(translation const &) = default;
|
||||||
|
|
||||||
vector_type vector() const;
|
matrix<T, N, N + 1> affine_matrix() const;
|
||||||
vector_type vector(vector_type v);
|
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;
|
||||||
point_type operator()(point_type p) const;
|
|
||||||
|
|
||||||
homogeneous_matrix_type homogeneous_matrix() const;
|
vector<T, N> operator()(vector<T, N> const & v) const;
|
||||||
|
point<T, N> operator()(point<T, N> const & p) const;
|
||||||
translation inverse() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
vector_type v_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
translation<T, D>::translation()
|
translation<T, N>::translation()
|
||||||
: translation(vector_type::zero())
|
: v{vector<T, N>::zero()}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
translation<T, D>::translation(vector_type v)
|
translation<T, N>::translation(vector<T, N> const & v)
|
||||||
: v_(v)
|
: v{v}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
vector<T, D> translation<T, D>::vector() const
|
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>
|
template <typename T, std::size_t N>
|
||||||
vector<T, D> translation<T, D>::vector(vector_type v)
|
matrix<T, N, N> translation<T, N>::linear_matrix() const
|
||||||
{
|
{
|
||||||
auto t = v_;
|
return matrix<T, N, N>::identity();
|
||||||
v_ = v;
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
vector<T, D> translation<T, D>::operator()(vector_type v) const
|
vector<T, N> translation<T, N>::translation_vector() const
|
||||||
{
|
{
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
point<T, D> translation<T, D>::operator()(point_type p) const
|
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>
|
template <typename T, std::size_t N>
|
||||||
matrix<T, D + 1, D + 1> translation<T, D>::homogeneous_matrix() const
|
affine_transform<T, N, N> translation<T, N>::transform() const
|
||||||
{
|
{
|
||||||
homogeneous_matrix_type m = homogeneous_matrix_type::identity();
|
return {affine_matrix()};
|
||||||
for (std::size_t i = 0; i < D; ++i)
|
|
||||||
m[i][D] = v_[i];
|
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t D>
|
template <typename T, std::size_t N>
|
||||||
translation<T, D> translation<T, D>::inverse() const
|
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/rotation.hpp>
|
||||||
#include <psemek/geom/permutation.hpp>
|
#include <psemek/geom/permutation.hpp>
|
||||||
#include <psemek/geom/scale.hpp>
|
#include <psemek/geom/scale.hpp>
|
||||||
#include <psemek/geom/homogeneous.hpp>
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|
@ -109,14 +108,16 @@ namespace psemek::geom
|
||||||
|
|
||||||
matrix<float, 4, 4> spherical_camera::view() const
|
matrix<float, 4, 4> spherical_camera::view() const
|
||||||
{
|
{
|
||||||
return
|
auto tr =
|
||||||
translation<float, 3>({0.f, 0.f, -distance}).homogeneous_matrix()
|
translation<float, 3>({0.f, 0.f, -distance}).transform()
|
||||||
* homogeneous(swap<float, 3>(1, 2).matrix())
|
* swap<float, 3>(1, 2).transform()
|
||||||
* homogeneous(scale<float, 3>({1.f, -1.f, 1.f}).matrix())
|
* scale<float, 3>({1.f, -1.f, 1.f}).transform()
|
||||||
* homogeneous(plane_rotation<float, 3>(1, 2, elevation_angle).matrix())
|
* plane_rotation<float, 3>(1, 2, elevation_angle).transform()
|
||||||
* homogeneous(plane_rotation<float, 3>(1, 0, azimuthal_angle).matrix())
|
* plane_rotation<float, 3>(1, 0, azimuthal_angle).transform()
|
||||||
* translation<float, 3>({ -target[0], -target[1], -target[2] }).homogeneous_matrix()
|
* translation<float, 3>({ -target[0], -target[1], -target[2] }).transform()
|
||||||
;
|
;
|
||||||
|
|
||||||
|
return tr.homogeneous_matrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue