Program Listing for File lerp.hpp¶
↰ Return to documentation for file (include/ripple/math/lerp.hpp
)
#ifndef RIPPLE_MATH_LERP_HPP
#define RIPPLE_MATH_LERP_HPP
#include "math.hpp"
#include <ripple/container/vec.hpp>
#include <ripple/iterator/iterator_traits.hpp>
#include <ripple/utility/range.hpp>
namespace ripple::math {
/*==--- [1d lerp] ----------------------------------------------------------==*/
template <
typename Iterator,
typename Weights,
array_size_enable_t<Weights, 1> = 0>
ripple_all auto lerp(Iterator&& it, const Weights& weights) noexcept ->
typename iterator_traits_t<Iterator>::CopyType {
static_assert(
is_iterator_v<Iterator>, "Linear interpolation requires an iterator.");
using value_t = std::decay_t<decltype(weights[0])>;
// Comptute values used for the interpolation:
const auto sign = math::sign(weights[dimx()]);
const auto abs_w = std::abs(weights[dimx()]);
const auto abs_off = std::floor(abs_w);
const auto off = sign * abs_off;
const auto factor = abs_w - abs_off;
return (*it.offset(dimx(), off)) * (value_t(1) - factor) +
(*it.offset(dimx(), off + sign)) * factor;
}
/*==--- [2d lerp] ----------------------------------------------------------==*/
template <
typename Iterator,
typename Weights,
array_size_enable_t<Weights, 2> = 0>
ripple_all auto
lerp(const Iterator& it, const Weights& weights) noexcept ->
typename iterator_traits_t<Iterator>::CopyType {
static_assert(
is_array_v<Weights>, "Linear interpolation requires a weight array.");
static_assert(
array_traits_t<Weights>::size,
"Iterator dimensionality must match size of weight array.");
using T = std::decay_t<decltype(weights[0])>;
// Compute offset params:
const T absx = std::abs(weights[dimx()]);
const T fl_absx = std::floor(absx);
const int sign_x = math::sign(weights[dimx()]);
const int offx = sign_x * fl_absx;
const T absy = std::abs(weights[dimy()]);
const T fl_absy = std::floor(absy);
const int sign_y = math::sign(weights[dimy()]);
const int offy = sign_y * fl_absy;
// Compute the factors:
const T wx = absx - fl_absx;
const T wy = absy - fl_absy;
const T fx = T{1} - wx;
const T fy = T{1} - wy;
// clang-format off
auto a = it.offset(dimx(), offx).offset(dimy(), offy);
return
(*a) * (fx * fy)
+ (*a.offset(dimx(), sign_x)) * (wx * fy)
+ (*a.offset(dimy(), sign_y)) * (wy * fx)
+ (*a.offset(dimx(), sign_x)
.offset(dimy(), sign_y)) * (wx * wy);
// clang-format on
}
/*==--- [3d lerp] ----------------------------------------------------------==*/
template <
typename Iterator,
typename Weights,
array_size_enable_t<Weights, 3> = 0>
ripple_all auto lerp(Iterator&& it, const Weights& weights) ->
typename iterator_traits_t<Iterator>::CopyType {
static_assert(
is_array_v<Weights>, "Linear interpolation requires a weight array.");
static_assert(
array_traits_t<Weights>::size == 3,
"Iterator dimensionality must match size of weight array.");
using T = std::decay_t<decltype(weights[0])>;
// Compute offset params:
const T absx = std::abs(weights[dimx()]);
const T fl_absx = std::floor(absx);
const int sign_x = math::sign(weights[dimx()]);
const int offx = sign_x * fl_absx;
const T absy = std::abs(weights[dimy()]);
const T fl_absy = std::floor(absy);
const int sign_y = math::sign(weights[dimy()]);
const int offy = sign_y * fl_absy;
const T absz = std::abs(weights[dimz()]);
const T fl_absz = std::floor(absz);
const int sign_z = math::sign(weights[dimz()]);
const int offz = sign_z * fl_absz;
// Compute the factors:
const T wx = absx - fl_absx;
const T wy = absy - fl_absy;
const T wz = absz - fl_absz;
const T fx = T{1} - wx;
const T fy = T{1} - wy;
const T fz = T{1} - wz;
// Offset to the close (c) and far (f) cell in z plane:
auto c = it.offset(dimx(), offx).offset(dimy(), offy).offset(dimz(), offz);
auto f = c.offset(dimz(), sign_z);
// clang-format off
return
(*c) * (fx * fy * fz) +
(*c.offset(dimx(), sign_x)) * (wx * fy * fz) +
(*c.offset(dimy(), sign_y)) * (wy * fx * fz) +
(*c.offset(dimx(), sign_x).offset(dimy(), sign_y)) * (wx * wy * fz) +
(*f) * (fx * fy * wz) +
(*f.offset(dimx(), sign_x)) * (wx * fy * wz) +
(*f.offset(dimy(), sign_y)) * (wy * fx * wz) +
(*f.offset(dimx(), sign_x).offset(dimy(), sign_y)) * (wx * wy * wz);
// clang-format on
}
} // namespace ripple::math
#endif // RIPPLE_MATH_LERP_HPP