• Docs >
  • Program Listing for File lerp.hpp
Shortcuts

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

Docs

Access comprehensive developer documentation for Ripple

View Docs

Tutorials

Get tutorials to help with understand all features

View Tutorials

Examples

Find examples to help get started

View Examples