G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsBSpline.h
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsCore/gsLinearAlgebra.h>
17 #include <gsCore/gsGeometry.h>
18 
19 #include <gsNurbs/gsBSplineBasis.h>
20 #include <gsNurbs/gsBoehm.h>
22 
23 #include <gsUtils/gsPointGrid.h>
24 
25 namespace gismo {
26 namespace internal {
27 
28 template<class T>
29 struct gsCurveIntersectionResult;
30 
31 } // namespace internal
32 } // namespace gismo
33 
34 namespace gismo
35 {
36 
49 template<class T>
50 class gsBSpline : public gsGeoTraits<1,T>::GeometryBase
51 {
52 public:
53  typedef gsKnotVector<T> KnotVectorType;
54 
55  typedef typename gsGeoTraits<1,T>::GeometryBase Base;
56 
57  typedef gsBSplineBasis<T> Basis;
58 
60  typedef memory::shared_ptr< gsBSpline > Ptr;
61 
63  typedef memory::unique_ptr< gsBSpline > uPtr;
64 
65 public:
66 
68  gsBSpline() { }
69 
70  // enable swap
71  using gsGeometry<T>::swap;
72 
74  gsBSpline( const Basis & basis, gsMatrix<T> coefs )
75  : Base( basis, give(coefs) )
76  {
77  if( this->basis().isPeriodic() )
78  this->basis().expandCoefs(m_coefs);
79  }
80 
82  gsBSpline(KnotVectorType KV, gsMatrix<T> coefs, bool periodic = false )
83  {
84  this->m_basis = new Basis(give(KV));
85  m_coefs.swap(coefs);
86 
87  if( periodic )
88  {
89  const index_t sz = this->basis().size();
90 
91  this->basis().setPeriodic();
92 
93  if ( m_coefs.rows() == sz )
94  {
95  this->basis().trimCoefs(m_coefs);
96  }
97  else if ( m_coefs.rows() == this->basis().size() )
98  {
99  this->basis().expandCoefs(m_coefs);
100  }
101  else
102  {
103  GISMO_ERROR("Wrong number of coefficients for periodic basis.");
104  }
105  }
106  else // non-periodic
107  {
108  if( this->m_coefs.rows() + KV.degree() + 1 != static_cast<int>( this->knots().size() ) )
109  gsWarn << "gsBSpline Warning: #Knots="<< this->knots().size()<< ", #coefs="<< this->m_coefs.rows() <<"\n";
110  }
111  }
112 
113 
124  gsBSpline(T u0, T u1, unsigned interior, int degree,
125  gsMatrix<T> coefs, unsigned mult_interior=1, bool periodic = false)
126  {
127  this->m_basis = new Basis(u0, u1, interior, degree, mult_interior, periodic );
128  if( periodic )
129  {
130  GISMO_ASSERT( this->basis().numCrossingFunctions() == 1,
131  "Knot vector with clamped knots should lead to m_periodic == 1.");
132 
133  this->m_coefs = this->basis().perCoefs(coefs);
134  GISMO_ASSERT( this->m_coefs.rows() >= this->basis().size(),
135  "You should give at least as many coefficients as the size of the basis after converting to periodic.");
136  if( this->m_coefs.rows() > this->basis().size() )
137  gsWarn << "Some of the last coefficients are going to be lost during conversion to periodic basis.\n";
138  }
139  else // non-periodic
140  {
141  this->m_coefs.swap(coefs);
142  GISMO_ASSERT( this->m_coefs.rows() == this->basis().size(),
143  "Number of coefficients does not match the size of the basis.");
144  }
145  }
146 
147  GISMO_CLONE_FUNCTION(gsBSpline)
148 
149  GISMO_BASIS_ACCESSORS
150 
151 public:
152 
154  std::ostream &print(std::ostream &os) const
155  {
156  os << "BSpline curve "<< "of degree "<< this->basis().degree()<< ", "<< this->basis().knots() <<".\n";
157  os << "with control points "<< this->m_coefs.row(0)<<" ... "<<this->m_coefs.bottomRows(1) << ".\n";
158  if( this->basis().isPeriodic() )
159  os << "Periodic with overlay " << this->basis().numCrossingFunctions() << ".\n";
160  return os;
161  }
162 
164  T domainStart() const { return *this->basis().knots().domainBegin(); }
165 
167  T domainEnd() const { return *this->basis().knots().domainEnd(); }
168 
170  KnotVectorType & knots(const int i = 0)
171  {
172  GISMO_UNUSED(i);
173  GISMO_ASSERT( i==0, "Requested knots of invalid direction "<< i );
174  return this->basis().knots();
175  }
176 
178  const KnotVectorType & knots(const int i = 0) const
179  {
180  GISMO_UNUSED(i);
181  GISMO_ASSERT( i==0, "Requested knots of invalid direction "<< i );
182  return this->basis().knots();
183  }
184 
186  short_t degree(short_t i = 0) const
187  {
188  GISMO_UNUSED(i);
189  GISMO_ASSERT( i==0, "Requested knots of invalid direction "<< i );
190  return this->basis().degree();
191  }
192 
193  // compatible curves: same degree, same first/last p+1 knots
194  void isCompatible( gsGeometry<T> * )
196 
197  // compatible curves: same degree, same first/last p+1 knots
198  void makeCompatible( gsGeometry<T> * )
200 
201 
203  void merge( gsGeometry<T> * otherG );
204 
211  gsBSpline<T> segmentFromTo(T u0, T u1, T tolerance=1e-15) const;
212 
219  void splitAt(T u0, gsBSpline<T>& left, gsBSpline<T>& right, T tolerance=1e-15) const;
220 
224  gsMultiPatch<T> toBezier(T tolerance=1e-15) const;
225 
232  std::vector<internal::gsCurveIntersectionResult<T>> intersect(const gsBSpline<T>& other, T tolerance = 1e-5, T curvatureTolerance=1+1e-6) const;
233 
237  T pseudoCurvature() const;
238 
241  void insertKnot( T knot, index_t i = 1);
242 private:
243  // Resolve hidden overload w.r.t. gsGeometry
244  virtual void insertKnot( T knot, index_t dir, index_t i = 1);
245 public:
246 
252  template <class It>
253  void insertKnots( It inBegin, It inEnd)
254  {
255  if( this->basis().isPeriodic() )
256  {
257  // We assume we got valid (i.e., non-NULL) iterators; I don't think we have a reasonable way to test it in GISMO_ASSERT.
258 
259  GISMO_ASSERT( (*inBegin > *(this->knots().begin()))
260  && (*(inEnd-1) < *(this->knots().end()-1)),
261  "Please, ask me to insert knots inside the knot interval only." );
262 
263  std::vector<T> newKnots(inBegin,inEnd);
264 
265  // It can happen that user would ask us to insert knots outside the active range.
266  // Should it happen, we shift the values and then sort the knot vector to remain non-decreasing.
267 
268  T activeLength = this->basis()._activeLength();
269  T blue1 = *(this->basis().knots().begin() + this->degree() );
270  T blue2 = *(this->basis().knots().end() - this->degree() );
271  typename std::vector<T>::iterator begin = newKnots.begin();
272  typename std::vector<T>::iterator end = newKnots.end();
273  for( typename std::vector<T>::iterator it = begin; it != end; ++it )
274  {
275  if( *it < blue1 )
276  *it += activeLength;
277  else if( *it > blue2 )
278  *it -= activeLength;
279  else if( (*it == blue1) || (*it == blue2) )
280  {
281  // I would like to erase it and go on but for that the iterator is not enough.
282  // ANGELOS, wouldn't it be better to put a GISMO_ASSERT here instead? Or throw an exception?
283  gsWarn << "Interrupting insertKnots(): Cannot insert value equal to the p+1st knot from the beginning or end into a periodic curve.\n";
284  return;
285  }
286  }
287  /* // This way it would be nicer but it does not cover all the dubious cases.
288  for( It it = begin; *it < blue1; ++it )
289  *it += activeLength;
290  for( It it = end-1; *it > blue2; --it )
291  *it -= activeLength;*/
292 
293  std::sort( begin, end );
294 
295  // We copy some of the control points to pretend for a while that the basis is not periodic.
296  //gsMatrix<T> trueCoefs = this->basis().perCoefs( this->coefs() );
297  gsBoehmRefine( this->basis().knots(), this->coefs(), this->degree(), begin, end );
298  //this->basis().enforceOuterKnotsPeriodic();
299  //this->coefs() = trueCoefs; // Isn't this memory-leaking?
300  // Periodic basis is restored using the so-called Student's Algorithm: forget as much as possible =).
301  //this->coefs().conservativeResize( this->basis().size(), this->coefs().cols() );
302  }
303  else // non-periodic
304  gsBoehmRefine( this->basis().knots(), this->coefs(), this->degree(), inBegin, inEnd);
305  }
306 
307  // Look at gsGeometry class for a description
308  void degreeElevate(short_t const i = 1, short_t const dir = -1);
309 
312  // Under Construction..( TO DO )
313  bool contains( gsMatrix<T> const & p, T const & tol = 1e-6 )
314  {
315  assert( p.cols()==1 );
316  gsBSplineSolver<T> slv;
317  std::vector<T> roots;
318  short_t dim = this->geoDim();
319  gsMatrix<T> ev, tmp(1,1);
320  int i(1);
321 
322  slv.allRoots( *this, roots, 0, p(0,0), 1e-6, 100);
323  for ( typename std::vector<T>::const_iterator it=roots.begin();
324  it != roots.end(); ++it)
325  {
326  tmp(0,0)= *it;
327  this->eval_into(tmp,ev);
328  for (i=1; i!=dim; ++i )
329  if ( math::abs( ev(i,0) - p(i,0) ) > tol )
330  break;
331  if (i==dim)
332  return true;
333  }
334  return false;
335  }
336 
338  gsMatrix<T> sample(int npoints = 50) const
339  {
340  gsMatrix<T> images;
341  gsMatrix<T> interval = this->parameterRange();
342  const gsMatrix<T> pts = gsPointGrid(interval, npoints );
343  this->eval_into( pts, images );
344  return images;
345  }
346 
348  void setPeriodic(bool flag = true)
349  {
350  this->basis().setPeriodic(flag);
351  this->m_coefs = this->basis().perCoefs( this->m_coefs );
352  }
353 
354  inline int numCoefs() const { return this->m_coefs.rows() - this->basis().numCrossingFunctions(); }
355 
356  inline bool isPeriodic() const { return this->basis().isPeriodic(); }
357 
358 
360  bool isClosed(T tol = 1e-10) const
361  {
362  return ( this->basis().isPeriodic() ||
363  (m_coefs.row(0) - m_coefs.row(m_coefs.rows()-1)).squaredNorm()<tol );
364  }
365 
368  bool isOn(gsMatrix<T> const &u, T tol = 1e-3) const;
369 
372  bool isPatchCorner(gsMatrix<T> const &v, T tol = 1e-3) const;
373 
377  void findCorner(const gsMatrix<T> & v,
378  gsVector<index_t,1> & curr,
379  T tol = 1e-3);
380 
384  void setOriginCorner(gsMatrix<T> const &v);
385 
389  void setFurthestCorner(gsMatrix<T> const &v);
390 
391  void swapDirections(const unsigned i, const unsigned j);
392 
393 protected:
394 
395  using Base::m_coefs;
396 
397  // TODO Check function
398  // check function: check the coefficient number, degree, knot vector ...
399 }; // class gsBSpline
400 
401 
402 #ifdef GISMO_WITH_PYBIND11
403 
407  void pybind11_init_gsBSpline(pybind11::module &m);
408 
409 #endif // GISMO_WITH_PYBIND11
410 
411 
412 /*
413 // Product of spline functions
414 template<class T>
415 gsBSpline<T> operator*(const gsBSpline<T> & lhs, const gsBSpline<T> & rhs)
416 {
417  // Note: quick-fix implementation. Better algorithms exist
418  gsKnotVector<T> kv = lhs.knots().knotUnion( lhs.knots() );
419  kv.degreeElevate( lhs.degree() + rhs.degree() - kv.degree() );
420 
421  gsMatrix<T> pts;
422  kv.greville_into(pts);
423  const gsMatrix<T> ev = (lhs.eval(pts)).array() * (rhs.eval(pts)).array();
424 
425  // fixme: avoid temporaries here
426  return *(static_cast<gsBSpline<T>*>(gsBSplineBasis<T>(kv).interpolateData(ev,pts)));
427 }
428 */
429 
430 } // namespace gismo
431 
432 
433 #ifndef GISMO_BUILD_LIB
434 #include GISMO_HPP_HEADER(gsBSpline.hpp)
435 #endif
bool isPatchCorner(gsMatrix< T > const &v, T tol=1e-3) const
Return true if point u is an endpoint (corner) of the curve with tolerance tol.
Definition: gsBSpline.hpp:291
gsMatrix< T > sample(int npoints=50) const
Sample npoints uniformly distributed (in parameter domain) points on the curve.
Definition: gsBSpline.h:338
Abstract base class representing a geometry map.
Definition: gsGeometry.h:92
void merge(gsGeometry< T > *otherG)
Merge other B-spline into this one.
Definition: gsBSpline.hpp:29
gsMatrix< T > m_coefs
Coefficient matrix of size coefsSize() x geoDim()
Definition: gsGeometry.h:624
T pseudoCurvature() const
Definition: gsBSpline.hpp:189
#define GISMO_NO_IMPLEMENTATION
Definition: gsDebug.h:129
gsBSpline(const Basis &basis, gsMatrix< T > coefs)
Construct B-Spline by basis and coefficient matrix.
Definition: gsBSpline.h:74
gsMatrix< T > parameterRange() const
Returns the range of parameters as a matrix with two columns, [lower upper].
Definition: gsGeometry.hpp:198
gsBasis< T > * m_basis
Pointer to the basis of this geometry.
Definition: gsGeometry.h:627
#define short_t
Definition: gsConfig.h:35
gsBSpline()
Default empty constructor.
Definition: gsBSpline.h:68
bool isOn(gsMatrix< T > const &u, T tol=1e-3) const
Return true if point u is on the curve with tolerance tol.
Definition: gsBSpline.hpp:265
void setFurthestCorner(gsMatrix< T > const &v)
Modifies the parameterization such that the point v is the ending point of the curve. Assumes that v is either the starting or the ending point of the curve.
Definition: gsBSpline.hpp:326
Boehm&#39;s algorithm for knot insertion.
void gsBoehmRefine(KnotVectorType &knots, Mat &coefs, int p, ValIt valBegin, ValIt valEnd, bool update_knots=true)
Definition: gsBoehm.hpp:163
S give(S &x)
Definition: gsMemory.h:266
Provides declaration of Geometry abstract interface.
memory::unique_ptr< gsBSpline > uPtr
Unique pointer for gsBSpline.
Definition: gsBSpline.h:63
#define index_t
Definition: gsConfig.h:32
T domainEnd() const
Returns the end value of the domain of the basis.
Definition: gsBSpline.h:167
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
A B-spline function of one argument, with arbitrary target dimension.
Definition: gsBSpline.h:50
void setOriginCorner(gsMatrix< T > const &v)
Modifies the parameterization such that the point v is the starting point of the curve. Assumes that v is either the starting or the ending point of the curve.
Definition: gsBSpline.hpp:315
A univariate B-spline basis.
Definition: gsBSplineBasis.h:694
void insertKnot(T knot, index_t i=1)
Definition: gsBSpline.hpp:249
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition: gsVector.h:35
#define gsWarn
Definition: gsDebug.h:50
Provides declaration of BSplineBasis class.
bool isClosed(T tol=1e-10) const
Returns true if this curve is closed.
Definition: gsBSpline.h:360
gsMatrix< T > gsPointGrid(gsVector< T > const &a, gsVector< T > const &b, gsVector< unsigned > const &np)
Construct a Cartesian grid of uniform points in a hypercube, using np[i] points in direction i...
Definition: gsPointGrid.hpp:82
Interface for the set of functions defined on a domain (the total number of functions in the set equa...
Definition: gsFuncData.h:23
std::ostream & print(std::ostream &os) const
Prints the object as a string.
Definition: gsBSpline.h:154
KnotVectorType & knots(const int i=0)
Returns a reference to the knot vector.
Definition: gsBSpline.h:170
void setPeriodic(bool flag=true)
Tries to convert the curve into periodic.
Definition: gsBSpline.h:348
std::vector< internal::gsCurveIntersectionResult< T > > intersect(const gsBSpline< T > &other, T tolerance=1e-5, T curvatureTolerance=1+1e-6) const
Definition: gsBSpline.hpp:156
const KnotVectorType & knots(const int i=0) const
Returns a (const )reference to the knot vector.
Definition: gsBSpline.h:178
void degreeElevate(short_t const i=1, short_t const dir=-1)
Elevate the degree by the given amount i for the direction dir. If dir is -1 then degree elevation is...
Definition: gsBSpline.hpp:347
void insertKnots(It inBegin, It inEnd)
Definition: gsBSpline.h:253
gsMultiPatch< T > toBezier(T tolerance=1e-15) const
Definition: gsBSpline.hpp:138
void eval_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluate the function at points u into result.
Definition: gsGeometry.hpp:166
#define GISMO_UNUSED(x)
Definition: gsDebug.h:112
Provides functions to generate structured point data.
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
Class for representing a knot vector.
Definition: gsKnotVector.h:79
memory::shared_ptr< gsBSpline > Ptr
Shared pointer for gsBSpline.
Definition: gsBSpline.h:60
This is the main header file that collects wrappers of Eigen for linear algebra.
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4488
Definition: gsBSplineSolver.h:113
void findCorner(const gsMatrix< T > &v, gsVector< index_t, 1 > &curr, T tol=1e-3)
returns the tensor-index curr of the corner control point v, or an invalid index if the corner is not...
Definition: gsBSpline.hpp:298
Provides classes and functions to solve equations involving B-splines.
gsBSpline(T u0, T u1, unsigned interior, int degree, gsMatrix< T > coefs, unsigned mult_interior=1, bool periodic=false)
Construct a B-spline from an interval and knot vector specification.
Definition: gsBSpline.h:124
gsBSpline< T > segmentFromTo(T u0, T u1, T tolerance=1e-15) const
Definition: gsBSpline.hpp:87
virtual const gsBasis< T > & basis() const =0
Returns a const reference to the basis of the geometry.
T domainStart() const
Returns the starting value of the domain of the basis.
Definition: gsBSpline.h:164
gsBSpline(KnotVectorType KV, gsMatrix< T > coefs, bool periodic=false)
Construct B-Spline by a knot vector and coefficient matrix.
Definition: gsBSpline.h:82
short_t degree(short_t i=0) const
Returns the degree of the B-spline.
Definition: gsBSpline.h:186
bool contains(gsMatrix< T > const &p, T const &tol=1e-6)
Returns true iff the point p is contained (approximately) on the curve, with the given tolerance...
Definition: gsBSpline.h:313
short_t geoDim() const
Dimension n of the absent physical space.
Definition: gsGeometry.h:292
void splitAt(T u0, gsBSpline< T > &left, gsBSpline< T > &right, T tolerance=1e-15) const
Definition: gsBSpline.hpp:255
gsMatrix< T > & coefs()
Definition: gsGeometry.h:340