#include #include namespace hgl { namespace graph { template Spline::Spline( int k, SplineNode node_type) : _node_type(node_type), _k(k), _point( _k ), _vec( _k-1 ), _node( _k + _point.size() ) { assert_splines(); } // ----------------------------------------------------------------------------- template void Spline::set_ctrl_points(const std::vector& point) { _point = point; _vec.resize(_point.size() - 1); for(int i = 0; i < (int)_vec.size(); ++i) _vec[i] = _point[i + 1] - _point[i]; set_nodal_vector(); assert_splines(); for(int i = 0; i < (int)_vec.size(); ++i) _vec[i] /= _node[_k+i] - _node[i+1]; } // ----------------------------------------------------------------------------- template void Spline::get_ctrl_points(std::vector& points) const { points = _point; } // ----------------------------------------------------------------------------- /// The the nodal vector type template void Spline::set_node_type( SplineNode type) { _node_type = type; set_nodal_vector(); assert_splines(); } // ----------------------------------------------------------------------------- template Point_t Spline::eval_f(Real_t u) const { u = std::max(std::min(u, (Real_t)1), (Real_t)0); // clamp between [0 1] return eval(u, _point, _k, _node); } // ----------------------------------------------------------------------------- template Point_t Spline::eval_df(Real_t u) const { u = std::max(std::min(u, (Real_t)1), (Real_t)0); // clamp between [0 1] return eval(u, _vec, (_k-1), _node, 1) * (Real_t)(_k-1); } // ----------------------------------------------------------------------------- template void Spline::assert_splines() const { assert( _k > 1); assert((int)_point.size() >= _k ); assert(_node. size() == (_k + _point.size()) ); assert(_point.size() == (_vec.size() + 1) ); } // ----------------------------------------------------------------------------- template void Spline::set_nodal_vector() { if( _node_type == SplineNode::OPEN_UNIFORM) set_node_to_open_uniform(); else if( _node_type == spline::eUNIFORM ) set_node_to_uniform(); } // ----------------------------------------------------------------------------- template void Spline::set_node_to_uniform() { const int n = _point.size() - 1; _node.resize( _k + n + 1 ); Real_t step = (Real_t)1 / (Real_t)(n-_k+2); for (int i = 0; i < (int)_node.size(); ++i){ _node[i] = ((Real_t)i) * step - step * (Real_t)(_k-1); } } // ----------------------------------------------------------------------------- template void Spline::set_node_to_open_uniform() { _node.resize( _k + _point.size() ); int acc = 1; for (int i = 0; i < (int)_node.size(); ++i) { if(i < _k) _node[i] = 0.; else if( i >= ((int)_point.size() + 1) ) _node[i] = 1.; else{ _node[i] = (Real_t)acc / (Real_t)(_point.size() + 1 - _k); acc++; } } } // ----------------------------------------------------------------------------- template Point_t Spline:: eval(Real_t u, const std::vector& point, int k, const std::vector& node, int off) const { assert( k > 1); assert((int)point.size() >= k ); assert_splines(); int dec = 0; // TODO: better search with dychotomi ? // TODO: check for overflow while( u > node[dec + k + off] ) dec++; // TODO: use buffers in attributes for better performances ? std::vector p_rec(k, Point_t()); for(int i = dec, j = 0; i < (dec + k); ++i, ++j) p_rec[j] = point[i]; std::vector node_rec(k + k - 2, (Real_t)0); for(int i = (dec + 1), j = 0; i < (dec + k + k - 1); ++i, ++j) node_rec[j] = node[i + off]; return eval_rec(u, p_rec, k, node_rec); } // ----------------------------------------------------------------------------- template Point_t Spline:: eval_rec(Real_t u, std::vector p_in, int k, std::vector node_in) const { if(p_in.size() == 1) return p_in[0]; // TODO: use buffers in attributes for better performances ? std::vector p_out(k - 1, Point_t()); for(int i = 0; i < (k - 1); ++i) { const Real_t n0 = node_in[i + k - 1]; const Real_t n1 = node_in[i]; const Real_t f0 = (n0 - u) / (n0 - n1); const Real_t f1 = (u - n1) / (n0 - n1); p_out[i] = p_in[i] * f0 + p_in[i + 1] * f1; } std::vector node_out(node_in.size() - 2); for(int i = 1, j = 0; i < ((int)node_in.size()-1); ++i, ++j) node_out[j] = node_in[i]; return eval_rec(u, p_out, (k - 1), node_out); } }//namespace graph }//namespace hgl