1 #ifndef VTESTBED_GEOMETRY_BASIS_SPLINE_HH     2 #define VTESTBED_GEOMETRY_BASIS_SPLINE_HH     4 #include <vtestbed/geometry/types.hh>     5 #include <vtestbed/linalg/linear_algebra.hh>    17         template <
class T, 
int N>
    21             using point_type = Vertex<T,N>;
    22             using element_type = Vertex<T,N+1>;
    24             using weight_type = T;
    30             using scalar_type = T;
    31             using value_type = element_type;
    32             using reference = value_type&;
    33             using const_reference = 
const value_type&;
    34             using size_type = size_t;
    39             T _x_min{0}, _x_max{1};
    52             _elements(elements), _knots(knots) {}
    56             Basis_spline(elements, make_knots(elements.size(), degree)) {}
    69                     make_knots(points.size(), degree)) {}
    77                 const auto m = num_knots()-1;
    78                 const auto n = num_points()-1;
    83             num_internal_knots()
 const {
    84                 const auto p = degree();
    85                 const auto m = num_knots()-1;
    96                 const auto& t = this->_knots;
    97                 const auto& c = this->_elements;
    98                 const auto p = this->degree();
   101                 if (k == t.size()) { 
return c.back(); }
   102                 if (k >= c.size()) { k = c.size()-1; }
   104                 for (size_type i=0; i<p+1; ++i) {
   105                     d[i] = multiply_by_weight(c[i+k-p]);
   107                 for (size_type r=1; r<p+1; ++r) {
   108                     for (size_type j=p; j>r-1; --j) {
   111                         T alpha = (x - t0) / (t1 - t0);
   112                         d[j] = (T{1} - alpha)*d[j-1] + alpha*d[j];
   115                 return divide_by_weight(d[p]);
   118             inline coefficient_array
   119             coefficients(T x)
 const {
   120                 const auto& t = this->_knots;
   121                 const auto& c = this->_elements;
   122                 const auto p = this->degree();
   123                 auto npoints = c.size();
   124                 coefficient_array coefs(npoints);
   127                 if (k == 0) { coefs.front() = 1; 
return coefs; }
   128                 if (k == t.size()) { coefs.back() = 1; 
return coefs; } 
   130                 for (size_type d=1; d<p+1; ++d) {
   131                     coefs[k-d] = ((t[k+1]-x) / (t[k+1]-t[k+1-d])) * coefs[k+1-d];
   132                     for (size_type i=k-d+1; i<k; ++i) {
   133                         coefs[i] = ((x-t[i]) / (t[i+d]-t[i]))*coefs[i] +
   134                             ((t[i+d+1]-x) / (t[i+d+1] - t[i+1])) * coefs[i+1];
   136                     coefs[k] = ((x-t[k]) / (t[k+d]-t[k]))*coefs[k];
   144                 auto& c = this->_elements;
   146                 auto delta = T{1}/(n-1);
   147                 for (
int k=0; k<N; ++k) {
   149                     for (
int i=0; i<n; ++i) {
   150                         const auto t = i*delta;
   151                         auto coefs = coefficients(t);
   152                         for (
int j=0; j<n; ++j) { lhs(i,j) = coefs[j]; }
   155                     for (
int i=0; i<n; ++i) { rhs(i) = c[i](k); }
   156                     rhs = solve(lhs, rhs);
   157                     for (
int i=0; i<n; ++i) { c[i](k) = rhs(i); }
   161             inline size_type size()
 const { 
return this->num_points(); }
   162             inline size_type num_points()
 const { 
return this->_elements.size(); }
   163             inline size_type num_knots()
 const { 
return this->_knots.size(); }
   164             inline const knot_array& knots()
 const { 
return this->_knots; }
   165             inline const element_array& elements()
 const { 
return this->_elements; }
   168             range(T min, T max) {
   173             inline static knot_array
   174             make_knots(size_type npoints, size_type degree) {
   175                 const auto n = npoints-1;
   176                 if (degree > n) { degree = n; }
   177                 const auto p = degree;
   178                 const auto m = n + p + 1;
   184                 const auto mreal = m+1-p-p;
   185                 T delta = T{1}/(mreal-1);
   186                 for (size_type i=0; i<p; ++i) { knots.emplace_back(0); }
   187                 for (size_type i=0; i<mreal; ++i) { knots.emplace_back(i*delta); }
   188                 for (size_type i=0; i<p; ++i) { knots.emplace_back(1); }
   192             inline static knot_array
   193             make_cyclic_knots(size_type npoints, size_type degree) {
   195                 const auto p = degree;
   196                 const auto n = npoints-1;
   197                 const auto m = n + p + 1;
   203                 const auto mreal = m+1-p-p;
   204                 T delta = T{1}/(mreal-1);
   205                 for (size_type i=0; i<p; ++i) { knots.emplace_back((p-i)*(-delta)); }
   206                 for (size_type i=0; i<mreal; ++i) { knots.emplace_back(i*delta); }
   207                 for (size_type i=0; i<p; ++i) { knots.emplace_back((mreal+i)*delta); }
   211             inline static element_type
   212             to_element(
const point_type& p, T weight) {
   214                 for (
int i=0; i<N; ++i) { elem(i) = p(i); }
   219             inline static point_type
   220             to_point(
const element_type& elem) {
   222                 for (
int i=0; i<N; ++i) { point(i) = elem(i); }
   229             locate(T& x, size_type& i)
 const {
   230                 x = _x_min + (_x_max - _x_min)*x;
   231                 const auto& knots = this->_knots;
   232                 const auto nknots = knots.size();
   233                 for (i=0; i<nknots; ++i) {
   241             inline static element_array
   242             make_elements(
const point_array& points, 
const weight_array& weights) {
   243                 if (points.size() != weights.size()) {
   246                 const auto npoints = points.size();
   248                 if (npoints == 0) { 
return elems; }
   249                 elems.reserve(npoints);
   250                 for (size_type i=0; i<npoints; ++i) {
   251                     elems.emplace_back(to_element(points[i], weights[i]));
   256             inline static element_array
   257             make_elements(
const point_array& points) {
   258                 const auto npoints = points.size();
   260                 if (npoints == 0) { 
return elems; }
   261                 elems.reserve(npoints);
   262                 for (size_type i=0; i<npoints; ++i) {
   263                     elems.emplace_back(to_element(points[i], T{1}));
   268             inline static element_type
   269             multiply_by_weight(element_type elem) {
   270                 if (elem(N) != T{}) {
   271                     for (
int i=0; i<N; ++i) { elem(i) *= elem(N); }
   276             inline static element_type
   277             divide_by_weight(element_type elem) {
   278                 if (elem(N) != T{}) {
   279                     for (
int i=0; i<N; ++i) { elem(i) /= elem(N); }
   291         template <
class T, 
int N>
   298             using typename basis_spline::value_type;
   299             using typename basis_spline::scalar_type;
   300             using typename basis_spline::size_type;
   308                     basis_spline::make_cyclic_knots(elements.size(), degree)) {}
   314                 for (size_type i=0; i<degree; ++i) { c.emplace_back(c[i]); }
   324 #endif // vim:filetype=cpp Closed non-uniform rational basis spline (NURBS).
 
Linear algebra (matrix/vector wrappers and solvers).
 
element_type operator()(T x) const
Uses de Boor's agorithm .
 
Non-uniform rational basis spline (NURBS).