G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsTensorNurbs.h
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsCore/gsGeometry.h>
18 
19 #include <gsTensor/gsTensorTools.h> // todo: move to hpp
20 
21 namespace gismo
22 {
23 
39 template<short_t d, class T>
40 class gsTensorNurbs : public gsGeoTraits<d,T>::GeometryBase
41 {
42 
43 public:
44  typedef gsKnotVector<T> KnotVectorType;
45 
46  typedef typename gsGeoTraits<d,T>::GeometryBase Base;
47 
48  typedef T Scalar_t;
49 
50  typedef gsTensorBSplineBasis<d,T> TBasis; // underlying tensor basis
51 
54 
55  // rational version of tensor basis (basis for this geometry)
57 
59  typedef typename gsBSplineTraits<static_cast<short_t>(d-1),T>::RatGeometry BoundaryGeometryType;
60  //typedef gsTensorNurbs<static_cast<short_t>(d-1),T> BoundaryGeometryType;
61 
63  typedef typename gsBSplineTraits<static_cast<short_t>(d-1),T>::RatBasis BoundaryBasisType;
64 
66  typedef memory::shared_ptr< gsTensorNurbs > Ptr;
67 
69  typedef memory::unique_ptr< gsTensorNurbs > uPtr;
70 
71 public:
72 
74  gsTensorNurbs() : Base() { }
75 
76  gsTensorNurbs( const Basis & basis, gsMatrix<T> coefs ) :
77  Base( basis, give(coefs) ) { }
78 
81  gsTensorNurbs( gsKnotVector<T> const& KV1, gsKnotVector<T> const & KV2,
82  gsMatrix<T> tcoefs)
83  {
84  GISMO_ASSERT(d==2, "Wrong dimension: tried to make a "<< d
85  <<"D NURBS using 2 knot-vectors.");
86 
87  gsBSplineBasis<T> * Bu = new gsBSplineBasis<T>(KV1);
88  gsBSplineBasis<T> * Bv = new gsBSplineBasis<T>(KV2);
89 
90  TBasis *tbasis = new TBasis(Bu,Bv) ;//d==2
91 
92  this->m_basis = new Basis(tbasis) ;
93  this->m_coefs.swap(tcoefs);
94  GISMO_ASSERT(tbasis->size()== m_coefs.rows(),
95  "Coefficient matrix for the NURBS does not have "
96  "the expected number of control points (rows)." );
97  }
98 
101  gsMatrix<T> tcoefs, gsMatrix<T> wgts)
102  {
103  GISMO_ASSERT(d==2, "Wrong dimension: tried to make a "<< d
104  <<"D NURBS using 2 knot-vectors.");
105 
106  gsBSplineBasis<T> * Bu = new gsBSplineBasis<T>(KV1);
107  gsBSplineBasis<T> * Bv = new gsBSplineBasis<T>(KV2);
108 
109  TBasis *tbasis = new TBasis(Bu,Bv) ;//d==2
110 
111  GISMO_ASSERT(tbasis->size()== tcoefs.rows(),
112  "Coefficient matrix for the NURBS does not have "
113  "the expected number of control points (rows)." );
114 
115  this->m_basis = new Basis(tbasis , give(wgts)) ;
116  this->m_coefs.swap(tcoefs);
117  }
118 
122  gsKnotVector<T> const & KV2,
123  gsKnotVector<T> const & KV3,
124  gsMatrix<T> tcoefs,
125  gsMatrix<T> wgts )
126  {
127  GISMO_ASSERT(d==3, "Wrong dimension: tried to make a "<< d
128  <<"D NURBS using 3 knot-vectors.");
129 
130  gsBSplineBasis<T> * Bu= new gsBSplineBasis<T>(KV1);
131  gsBSplineBasis<T> * Bv= new gsBSplineBasis<T>(KV2);
132  gsBSplineBasis<T> * Bw= new gsBSplineBasis<T>(KV3);
133  TBasis *tbasis = new TBasis(Bu,Bv,Bw) ;//d==3
134 
135  GISMO_ASSERT(tbasis->size()== tcoefs.rows(),
136  "Coefficient matrix for the NURBS does not have "
137  "the expected number of control points (rows)." );
138 
139  this->m_basis = new Basis(tbasis, give(wgts));
140  this->m_coefs.swap(tcoefs);
141  }
142 
146  gsKnotVector<T> const & KV2,
147  gsKnotVector<T> const & KV3,
148  gsMatrix<T> tcoefs)
149  {
150  GISMO_ASSERT(d==3, "Wrong dimension: tried to make a "<< d
151  <<"D NURBS using 3 knot-vectors.");
152 
153  gsBSplineBasis<T> * Bu= new gsBSplineBasis<T>(KV1);
154  gsBSplineBasis<T> * Bv= new gsBSplineBasis<T>(KV2);
155  gsBSplineBasis<T> * Bw= new gsBSplineBasis<T>(KV3);
156  TBasis *tbasis = new TBasis(Bu,Bv,Bw) ;//d==3
157 
158  GISMO_ASSERT(tbasis->size()== tcoefs.rows(),
159  "Coefficient matrix for the NURBS does not have "
160  "the expected number of control points (rows)." );
161 
162  this->m_basis = new Basis(tbasis) ;
163  this->m_coefs.swap(tcoefs);
164  }
165 
169  gsKnotVector<T> const & KV2,
170  gsKnotVector<T> const & KV3,
171  gsKnotVector<T> const & KV4,
172  gsMatrix<T> tcoefs,
173  gsMatrix<T> wgts )
174  {
175  GISMO_ASSERT(d==4, "Wrong dimension: tried to make a "<< d
176  <<"D NURBS using 4 knot-vectors.");
177 
178  std::vector< gsBSplineBasis<T>* > cbases;
179  cbases.reserve(4);
180  cbases.push_back(new gsBSplineBasis<T>(KV1) );
181  cbases.push_back(new gsBSplineBasis<T>(KV2) );
182  cbases.push_back(new gsBSplineBasis<T>(KV3) );
183  cbases.push_back(new gsBSplineBasis<T>(KV4) );
184  TBasis * tbasis = gsBSplineTraits<d,T>::Basis::New(cbases); //d==4
185 
186  GISMO_ASSERT(tbasis->size()== tcoefs.rows(),
187  "Coefficient matrix for the NURBS does not have "
188  "the expected number of control points (rows)." );
189 
190  this->m_basis = new Basis(tbasis, give(wgts));
191  this->m_coefs.swap(tcoefs);
192  }
193 
194  GISMO_BASIS_ACCESSORS
195 
196  public:
197 
198 // ***********************************************
199 // Virtual member functions required by the base class
200 // ***********************************************
201 
202  GISMO_CLONE_FUNCTION(gsTensorNurbs)
203 
204 
205  std::ostream &print(std::ostream &os) const
206  { os << "Tensor-NURBS geometry "<< "R^"<< this->parDim() <<
207  " --> R^"<< this->geoDim()<< ", #control pnts= "<< this->coefsSize() <<": "
208  << this->coef(0) <<" ... "<< this->coef(this->coefsSize()-1);
209  os << "\nweights: "
210  << this->basis().weights().at(0) <<" ... "
211  << this->basis().weights().at(this->coefsSize()-1)
212  <<"\n" ;
213  return os; }
214 
215 // ***********************************************
216 // Additional members for tensor NURBS
217 // ***********************************************
218 
220  const KnotVectorType & knots(const int i) const
221  { return this->basis().source().knots(i); }
222 
223  KnotVectorType & knots(const int i)
224  { return this->basis().source().knots(i); }
225 
227  void insertKnot( T knot, int dir, int i = 1)
228  {
229  GISMO_ASSERT( i>0, "multiplicity must be at least 1");
230  GISMO_ASSERT( dir >= 0 && static_cast<unsigned>(dir) < d,
231  "Invalid basis component "<< dir <<" requested for degree elevation" );
232 
233  // Combine control points and weights to n+1 dimensional "control points"
234  gsMatrix<T> projectiveCoefs = basis().projectiveCoefs(m_coefs, weights());
235 
236  // Dimension of physical space + 1 for the weights
237  const index_t n = projectiveCoefs.cols();
238 
239  gsTensorBSplineBasis<d,T> & tbs = this->basis().source();
241  tbs.size_cwise(sz); // Size of basis per (parametric) direction
242 
243  swapTensorDirection(0, dir, sz, projectiveCoefs );
244 
245  const index_t nc = sz.template tail<static_cast<short_t>(d-1)>().prod();
246  projectiveCoefs.resize( sz[0], n * nc );
247 
248  // Insert knot and update projective control points
249  gsBoehm(tbs.knots(dir), projectiveCoefs , knot, i, true );
250  sz[0] = projectiveCoefs.rows();
251 
252  // New number of coefficients
253  const index_t ncoef = sz.prod();
254  projectiveCoefs.resize(ncoef, n );
255 
256  swapTensorDirection(0, dir, sz, projectiveCoefs );
257 
258  // Unpack projective control points and update the coefs and weights of the original NURBS
259  basis().setFromProjectiveCoefs(projectiveCoefs, m_coefs, weights() );
260  }
261 
263  T & weight(int i) const { return this->basis().weight(i); }
264 
266  const gsMatrix<T> & weights() const { return this->basis().weights(); }
267 
269  gsMatrix<T> & weights() { return this->basis().weights(); }
270 
272  short_t degree(unsigned i) const
273  { return this->basis().source().component(i).degree(); }
274 
276  void reverse(unsigned k)
277  {
278  GISMO_ASSERT(d==2, "only 2D for now");
279 
280  gsVector<int> str(d);
281  gsVector<int> sz (d);
282 
283  gsTensorBSplineBasis<d,T> & tbsbasis = this->basis().source();
284 
285  sz[0] = tbsbasis.component(k ).size();
286  sz[1] = tbsbasis.component(!k).size();
287  str[0] = tbsbasis.source().stride( k );
288  str[1] = tbsbasis.source().stride(!k );
289 
290  gsMatrix<T> & w = tbsbasis.weights();
291 
292  for ( int i=0; i< sz[0]; i++ )
293  for ( int j=0; j< sz[1]/2; j++ )
294  {
295  this->m_coefs.row(i*str[0] + j*str[1] ).swap(
296  this->m_coefs.row(i*str[0] + (sz[1]-j-1)*str[1] )
297  );
298 
299  w.row(i*str[0] + j*str[1] ).swap(
300  w.row(i*str[0] + (sz[1]-j-1)*str[1] )
301  );
302  }
303  tbsbasis.component(k).reverse();
304  }
305 
309  void slice(index_t dir_fixed, T par, BoundaryGeometryType & result) const
310  {
311  GISMO_ASSERT(d-1>=0,"d must be greater or equal than 1");
312  GISMO_ASSERT(dir_fixed>=0 && static_cast<unsigned>(dir_fixed)<d,"cannot fix a dir greater than dim or smaller than 0");
313  // construct the d-1 basis
314  boxSide side(dir_fixed,0);
315  //typename gsTensorNurbsBasis<static_cast<short_t>(d-1),T>::uPtr tbasis = this->basis().boundaryBasis(side);
316  typename BoundaryBasisType::uPtr tbasis = this->basis().boundaryBasis(side);
317 
318  if(d==1)
319  {
320  gsMatrix<T> val(1,1),point;
321  val(0,0)=par;
322  this->eval_into(val,point);
323  //result = gsTensorNurbs<static_cast<short_t>(d-1), T>(*tbasis, point );
324  result = BoundaryGeometryType(*tbasis, point );
325  }
326  else
327  {
328  const int mult = this->basis().knots(dir_fixed).multiplicity(par);
329  const int degree = this->basis().degree(dir_fixed);
330 
332  if( mult>=degree )
333  {
334  // no knot insertion needed, just extract the right coefficients
335  const gsKnotVector<T>& knots = this->basis().knots(dir_fixed);
336  const index_t index = (knots.iFind(par) - knots.begin()) - this->basis().degree(dir_fixed);
337  gsVector<index_t,d> sizes;
338  this->basis().size_cwise(sizes);
339  constructCoefsForSlice<d, T>(dir_fixed, index, this->coefs(), sizes, coefs);
340  }
341  else
342  {
343  // clone the basis and inserting up to degree knots at par
344  gsTensorNurbs<d,T>* clone = this->clone().release();
345 
346  gsVector<index_t,d> intStrides;
347  this->basis().stride_cwise(intStrides);
349  clone->basis().knots(dir_fixed),clone->coefs(),par,dir_fixed,
350  intStrides.template cast<unsigned>(), degree-mult,true);
351 
352  // extract right ceofficients
353  const gsKnotVector<T>& knots = clone->basis().knots(dir_fixed);
354  const index_t index = (knots.iFind(par) - knots.begin()) - clone->basis().degree(dir_fixed);
355  gsVector<index_t,d> sizes;
356  clone->basis().size_cwise(sizes);
357  constructCoefsForSlice<d, T>(dir_fixed, index, clone->coefs(), sizes, coefs);
358  delete clone;
359  }
360 
361  // construct the object
362  //result = gsTensorBSpline<static_cast<short_t>(d-1),T>(*tbasis, give(coefs) );
363  //result = BoundaryGeometry(*tbasis, give(coefs) );
364  result = BoundaryGeometryType (*tbasis, coefs );
365  }
366  }
367 
368  void swapDirections(const unsigned i, const unsigned j)
369  {
371  this->basis().size_cwise(sz);
372  swapTensorDirection(i, j, sz, m_coefs);
373  this->basis().swapDirections(i,j);
374  }
375 
379  std::vector<gsGeometry<T>*> uniformSplit(index_t dir = -1) const
380  {
381  // We use the simple fact that a NURBS function in R^d is the central probjection
382  // of a spline function in R^{d+1} into R^d.
383  //
384  // Create a B-spline in R^{d+1} and split it
385  Basis& basis = static_cast<Basis&>(*m_basis); // Basis is here gsTensorNurbsBasis
386  std::vector<gsGeometry<T>*> result
388  // Turn the B-splines in R^{d+1} back into NURBS in R^d
389  for ( typename std::vector<gsGeometry<T>*>::iterator it = result.begin();
390  it != result.end(); ++it )
391  {
392  gsTensorBSpline<d,T>* spline = static_cast<gsTensorBSpline<d,T>*>(*it);
393  gsTensorNurbsBasis<d,T>* nurbsBasis = new gsTensorNurbsBasis<d,T>(spline->basis().clone().release());
395  nurbs->m_basis = nurbsBasis;
397  spline->coefs(),
398  nurbs->m_coefs,
399  nurbsBasis->weights()
400  );
401  delete *it;
402  *it = nurbs;
403  }
404  return result;
405  }
406 
407 
411  void splitAt(index_t dir,T xi, gsTensorNurbs<d,T>& left, gsTensorNurbs<d,T>& right) const
412  {
413  // We use the simple fact that a NURBS function in R^d is the central projection
414  // of a spline function in R^{d+1} into R^d.
415  //
416  // Create a B-spline in R^{d+1} and split it
417  Basis& basis = static_cast<Basis&>(*m_basis); // Basis is here gsTensorNurbsBasis
418  gsTensorBSpline<d,T> leftBS, rightBS;
419  gsTensorBSpline<d,T> tmp(basis.source(), basis.projectiveCoefs(m_coefs));
420 
421  // Use gsTensorBSpline::splitAt() with the projective coefs.
422  tmp.splitAt(dir, xi, leftBS, rightBS);
423 
424 
425  // Turn the B-splines in R^{d+1} back into NURBS in R^d
426  // gsTensorBSpline<d,T>* spline = static_cast<gsTensorBSpline<d,T>*>(*it);
427 
428  gsTensorNurbsBasis<d,T>* leftBasis = new gsTensorNurbsBasis<d,T>(leftBS.basis().clone().release());
429  gsTensorNurbs<d,T>* leftNurbs = new gsTensorNurbs<d,T>;
430  leftNurbs->m_basis = leftBasis;
431 
433  leftBS.coefs(),
434  leftNurbs->m_coefs,
435  leftBasis->weights());
436 
437  gsTensorNurbsBasis<d,T>* rightBasis = new gsTensorNurbsBasis<d,T>(rightBS.basis().clone().release());
438  gsTensorNurbs<d,T>* rightNurbs = new gsTensorNurbs<d,T>;
439  rightNurbs->m_basis = rightBasis;
440 
442  rightBS.coefs(),
443  rightNurbs->m_coefs,
444  rightBasis->weights());
445 
446 
447  left = gsTensorNurbs<d,T>( *leftBasis, leftNurbs->coefs() );
448  right = gsTensorNurbs<d,T>( *rightBasis, rightNurbs->coefs());
449  }
450 
451 protected:
452  // todo: check function: check the coefficient number, degree, knot vector ...
453 
456 
457 }; // class gsTensorNurbs
458 
459 
460 // ***********************************************
461 // ***********************************************
462 
463 
464 } // namespace gismo
index_t size() const
size
Definition: gsBSplineBasis.h:165
void gsBoehm(KnotVectorType &knots, Mat &coefs, T val, int r=1, bool update_knots=true)
Performs insertion of multiple knot on &quot;knots&quot; and coefficients &quot;coefs&quot;.
Definition: gsBoehm.hpp:29
memory::unique_ptr< gsTensorNurbsBasis > uPtr
Unique pointer for gsTensorNurbsBasis.
Definition: gsTensorNurbsBasis.h:69
Abstract base class representing a geometry map.
Definition: gsGeometry.h:92
gsBSplineBasis< T > Family_t
Family type.
Definition: gsTensorNurbs.h:53
gsMatrix< T > m_coefs
Coefficient matrix of size coefsSize() x geoDim()
Definition: gsGeometry.h:624
gsMatrix< T >::RowXpr coef(index_t i)
Returns the i-th coefficient of the geometry as a row expression.
Definition: gsGeometry.h:346
gsTensorNurbs(gsKnotVector< T > const &KV1, gsKnotVector< T > const &KV2, gsMatrix< T > tcoefs)
Definition: gsTensorNurbs.h:81
void reverse(unsigned k)
Toggle orientation wrt coordinate k.
Definition: gsTensorNurbs.h:276
Traits for BSplineBasis in more dimensions.
Definition: gsBSplineBasis.h:31
index_t size() const
Returns the number of elements in the basis.
Definition: gsTensorBasis.h:108
gsBasis< T > * m_basis
Pointer to the basis of this geometry.
Definition: gsGeometry.h:627
gsTensorNurbs(gsKnotVector< T > const &KV1, gsKnotVector< T > const &KV2, gsMatrix< T > tcoefs, gsMatrix< T > wgts)
Construct 2D tensor NURBS by knot vectors, degrees, weights and coefficient matrix.
Definition: gsTensorNurbs.h:100
#define short_t
Definition: gsConfig.h:35
A tensor product of d B-spline functions, with arbitrary target dimension.
Definition: gsTensorBSpline.h:44
void splitAt(index_t dir, T xi, gsTensorBSpline< d, T > &left, gsTensorBSpline< d, T > &right) const
Definition: gsTensorBSpline.hpp:449
A tensor product Non-Uniform Rational B-spline function (NURBS) of parametric dimension d...
Definition: gsTensorNurbs.h:40
gsTensorNurbs(gsKnotVector< T > const &KV1, gsKnotVector< T > const &KV2, gsKnotVector< T > const &KV3, gsMatrix< T > tcoefs, gsMatrix< T > wgts)
Definition: gsTensorNurbs.h:121
memory::unique_ptr< gsTensorNurbs > uPtr
Unique pointer for gsTensorNurbs.
Definition: gsTensorNurbs.h:69
void swapTensorDirection(int k1, int k2, gsVector< index_t, d > &sz, gsMatrix< T > &coefs)
Definition: gsTensorTools.h:129
Utility functions related to tensor-structured objects.
S give(S &x)
Definition: gsMemory.h:266
Provides declaration of Geometry abstract interface.
#define index_t
Definition: gsConfig.h:32
void size_cwise(gsVector< index_t, s > &result) const
The number of basis functions in the direction of the k-th parameter component.
Definition: gsTensorBasis.h:441
gsMatrix< T > projectiveCoefs(const gsMatrix< T > &coefs) const
Definition: gsRationalBasis.h:324
A tensor product B-spline basis.
Definition: gsTensorBSplineBasis.h:36
index_t coefsSize() const
Return the number of coefficients (control points)
Definition: gsGeometry.h:371
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
void splitAt(index_t dir, T xi, gsTensorNurbs< d, T > &left, gsTensorNurbs< d, T > &right) const
Definition: gsTensorNurbs.h:411
gsTensorNurbs(gsKnotVector< T > const &KV1, gsKnotVector< T > const &KV2, gsKnotVector< T > const &KV3, gsMatrix< T > tcoefs)
Definition: gsTensorNurbs.h:145
iterator iFind(const T u) const
Returns an iterator to the last occurrence of the knot at the beginning of the knot interval containi...
Definition: gsKnotVector.hpp:779
A univariate B-spline basis.
Definition: gsBSplineBasis.h:694
Provides declaration of TensorNurbsBasis abstract interface.
void slice(index_t dir_fixed, T par, BoundaryGeometryType &result) const
Definition: gsTensorNurbs.h:309
std::ostream & print(std::ostream &os) const
Prints the object as a string.
Definition: gsTensorNurbs.h:205
gsMatrix< T > & weights()
Returns the NURBS weights as non-const reference.
Definition: gsTensorNurbs.h:269
const KnotVectorType & knots(const int i) const
Returns a reference to the knot vector i.
Definition: gsTensorNurbs.h:220
Interface for the set of functions defined on a domain (the total number of functions in the set equa...
Definition: gsFuncData.h:23
Struct which represents a certain side of a box.
Definition: gsBoundary.h:84
virtual const gsBasis & source() const
Definition: gsBasis.h:704
virtual const gsMatrix< T > & weights() const
Only for compatibility reasons, with gsRationalBasis. It returns an empty matrix. ...
Definition: gsBasis.h:411
A tensor product Non-Uniform Rational B-spline (NURBS) basis.
Definition: gsTensorNurbsBasis.h:38
short_t parDim() const
Dimension d of the parameter domain (same as domainDim()).
Definition: gsGeometry.hpp:190
const SrcT & source() const
Returns the source basis of the rational basis.
Definition: gsRationalBasis.h:283
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
const gsMatrix< T > & weights() const
Returns the weights of the rational basis.
Definition: gsRationalBasis.h:290
short_t degree(unsigned i) const
Returns the degree of the basis wrt direction i.
Definition: gsTensorNurbs.h:272
memory::shared_ptr< gsTensorNurbs > Ptr
Shared pointer for gsTensorNurbs.
Definition: gsTensorNurbs.h:66
std::vector< gsGeometry< T > * > uniformSplit(index_t dir=-1) const
Definition: gsTensorNurbs.h:379
T & weight(int i) const
Access to i-th weight.
Definition: gsTensorNurbs.h:263
gsBSplineTraits< static_cast< short_t >d-1), T >::RatGeometry BoundaryGeometryType
Associated boundary geometry type.
Definition: gsTensorNurbs.h:59
void eval_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluate the function at points u into result.
Definition: gsGeometry.hpp:166
static void setFromProjectiveCoefs(const gsMatrix< T > &pr_coefs, gsMatrix< T > &coefs, gsMatrix< T > &weights)
Definition: gsRationalBasis.h:346
void insertKnot(T knot, int dir, int i=1)
Inserts knot knot at direction dir, i times.
Definition: gsTensorNurbs.h:227
Class for representing a knot vector.
Definition: gsKnotVector.h:79
iterator begin() const
Returns iterator pointing to the beginning of the repeated knots.
Definition: gsKnotVector.hpp:117
void gsTensorBoehm(KnotVectorType &knots, Mat &coefs, T val, int direction, gsVector< unsigned > str, int r=1, bool update_knots=true)
Definition: gsBoehm.hpp:245
const Basis_t & component(short_t dir) const
For a tensor product basis, return the (const) 1-d basis for the i-th parameter component.
Definition: gsTensorBSplineBasis.h:202
virtual const gsBasis< T > & basis() const =0
Returns a const reference to the basis of the geometry.
gsTensorNurbs(gsKnotVector< T > const &KV1, gsKnotVector< T > const &KV2, gsKnotVector< T > const &KV3, gsKnotVector< T > const &KV4, gsMatrix< T > tcoefs, gsMatrix< T > wgts)
Definition: gsTensorNurbs.h:168
short_t geoDim() const
Dimension n of the absent physical space.
Definition: gsGeometry.h:292
gsTensorNurbs()
Default empty constructor.
Definition: gsTensorNurbs.h:74
const gsMatrix< T > & weights() const
Returns the NURBS weights.
Definition: gsTensorNurbs.h:266
gsMatrix< T > & coefs()
Definition: gsGeometry.h:340