psemek/libs/geom/include/psemek/geom/scale.hpp

128 lines
2.7 KiB
C++

#pragma once
#include <psemek/geom/affine_transform.hpp>
namespace psemek::geom
{
template <typename T, std::size_t N>
struct scale
{
vector<T, N> s;
scale();
scale(T s);
scale(vector<T, N> const & s);
scale(scale const &) = default;
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;
affine_transform<T, N, N> transform() const;
vector<T, N> operator()(vector<T, N> v) const;
point<T, N> operator()(point<T, N> p) const;
private:
template <typename Matrix>
void fill_matrix(Matrix & m) const;
};
template <typename T, std::size_t N>
scale(vector<T, N>) -> scale<T, N>;
template <typename T, std::size_t N>
scale<T, N>::scale()
{
for (std::size_t i = 0; i < N; ++i)
s[i] = T{1};
}
template <typename T, std::size_t N>
scale<T, N>::scale(T s)
{
for (std::size_t i = 0; i < N; ++i)
this->s[i] = s;
}
template <typename T, std::size_t N>
scale<T, N>::scale(vector<T, N> const & s)
: s{s}
{}
template <typename T, std::size_t N>
matrix<T, N, N + 1> scale<T, N>::affine_matrix() const
{
auto result = matrix<T, N, N + 1>::identity();
fill_matrix(result);
return result;
}
template <typename T, std::size_t N>
matrix<T, N, N> scale<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> scale<T, N>::translation_vector() const
{
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>::identity();
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 N>
point<T, N> scale<T, N>::operator()(point<T, N> p) const
{
for (std::size_t i = 0; i < N; ++i)
p[i] *= s[i];
return p;
}
template <typename T, std::size_t N>
template <typename Matrix>
void scale<T, N>::fill_matrix(Matrix & m) const
{
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};
}
}