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).