#include "cubic_split.h"

template <
  typename DerivedC,
  typename DerivedK>
IGL_INLINE void igl::cubic_split(
  const Eigen::MatrixBase<DerivedC>& C,
  const typename DerivedC::Scalar & t,
  Eigen::PlainObjectBase<DerivedK>& C01,
  Eigen::PlainObjectBase<DerivedK>& C012,
  Eigen::PlainObjectBase<DerivedK>& C0123,
  Eigen::PlainObjectBase<DerivedK>&  C123,
  Eigen::PlainObjectBase<DerivedK>&   C23)
{
  const auto C0 = C.row(0);
  const auto C1 = C.row(1);
  const auto C2 = C.row(2);
  const auto C3 = C.row(3);

             C01 =  (C1 - C0) * t + C0;
  const auto C12 = ((C2 - C1) * t + C1).eval();
             C23 =  (C3 - C2) * t + C2;

  C012 = (C12 - C01) * t + C01;
  C123 = (C23 - C12) * t + C12;

  C0123 = (C123 - C012) * t + C012;
}

template <
  typename DerivedC,
  typename DerivedK>
IGL_INLINE void igl::cubic_split(
  const Eigen::MatrixBase<DerivedC>& C,
  const typename DerivedC::Scalar & t,
  Eigen::PlainObjectBase<DerivedK>& C1,
  Eigen::PlainObjectBase<DerivedK>& C2)
{
  using Scalar = typename DerivedC::Scalar;
  typedef Eigen::Matrix<Scalar,1,DerivedC::ColsAtCompileTime> RowVectorS;
  RowVectorS C01,C012,C0123,C123,C23;
  igl::cubic_split(C,t,C01,C012,C0123,C123,C23);
  C1.resize(4,C.cols());
  C1 << C.row(0),
        C01,
        C012,
        C0123;
  C2.resize(4,C.cols());
  C2 << C0123,
        C123,
        C23,
        C.row(3);
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::cubic_split<Eigen::Matrix<double, 4, -1, 1, 4, -1>, Eigen::Matrix<double, 4, 2, 1, 4, 2>>(Eigen::MatrixBase<Eigen::Matrix<double, 4, -1, 1, 4, -1>> const&, Eigen::Matrix<double, 4, -1, 1, 4, -1>::Scalar const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 1, 4, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 1, 4, 2>>&);
// generated by autoexplicit.sh
template void igl::cubic_split<Eigen::Matrix<double, 4, 2, 1, 4, 2>, Eigen::Matrix<double, 4, 2, 1, 4, 2>>(Eigen::MatrixBase<Eigen::Matrix<double, 4, 2, 1, 4, 2>> const&, Eigen::Matrix<double, 4, 2, 1, 4, 2>::Scalar const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 1, 4, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 1, 4, 2>>&);
// generated by autoexplicit.sh
template void igl::cubic_split<Eigen::Matrix<double, 4, 2, 0, 4, 2>, Eigen::Matrix<double, 4, 2, 1, 4, 2>>(Eigen::MatrixBase<Eigen::Matrix<double, 4, 2, 0, 4, 2>> const&, Eigen::Matrix<double, 4, 2, 0, 4, 2>::Scalar const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 1, 4, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 1, 4, 2>>&);
template void igl::cubic_split<Eigen::Matrix<double, 4, 2, 0, 4, 2>, Eigen::Matrix<double, 4, 2, 0, 4, 2>>(Eigen::MatrixBase<Eigen::Matrix<double, 4, 2, 0, 4, 2>> const&, Eigen::Matrix<double, 4, 2, 0, 4, 2>::Scalar const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 0, 4, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 2, 0, 4, 2>>&);
template void igl::cubic_split<Eigen::Matrix<double, 4, 2, 0, 4, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>>(Eigen::MatrixBase<Eigen::Matrix<double, 4, 2, 0, 4, 2>> const&, Eigen::Matrix<double, 4, 2, 0, 4, 2>::Scalar const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2>>&);
#endif
