G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsBSpline.hpp
Go to the documentation of this file.
1 
15 #pragma once
16 
18 #include <gsIO/gsXml.h>
20 
21 #include <gsCore/gsMultiPatch.h>
23 
24 namespace gismo
25 {
26 
27 
28 template<class T>
30 {
31  // See also gsNurbs::merge().
32  // check geometric dimension
33  GISMO_ASSERT(this->geoDim()==otherG->geoDim(),
34  "gsNurbs: cannot merge curves in different spaces ( R^"
35  << this->geoDim() << ", R^" << otherG->geoDim() << " ).");
36 
37  // check if the type of other is BSpline
38  gsBSpline * other = dynamic_cast<gsBSpline *>( otherG );
39  GISMO_ASSERT( other!=NULL, "Can only merge with B-spline curves.");
40  other= other->clone().release();
41 
42  GISMO_ASSERT( this ->basis().isPeriodic() == false &&
43  other->basis().isPeriodic() == false,
44  "Cannot merge a closed curve with anything." );
45 
46  // check degree
47  const short_t mDeg = this ->basis().degree();
48  const short_t oDeg = other->basis().degree();
49  const short_t deg = math::max(mDeg,oDeg);
50 
51  other->gsBSpline::degreeElevate( deg - oDeg ); // degreeElevate(0) does nothing (and very quickly)
52  this ->gsBSpline::degreeElevate( deg - mDeg );
53 
54  // check whether the resulting curve will be continuous
55  // TODO: ideally, the tolerance should be a parameter of the function
56  T tol = 1e-8;
57  gsMatrix<T> mValue = this ->eval(this ->support().col(1));
58  gsMatrix<T> oValue = other->eval(other->support().col(0));
59  bool continuous = gsAllCloseAbsolute(mValue,oValue,tol);
60 
61  // merge knot vectors.
62  KnotVectorType& mKnots = this ->basis().knots();
63  KnotVectorType& oKnots = other->basis().knots();
64  T lastKnot = mKnots.last();
65  if (continuous) // reduce knot multiplicity
66  {
67  // TODO check for clamped knot vectors otherwise
68  // we should do knot insertion beforehands
69  mKnots.remove(lastKnot);
70  }// else there is a knot of multiplicity deg + 1 at the discontinuity
71 
72  oKnots.addConstant(lastKnot-oKnots.first());
73  mKnots.append( oKnots.begin()+deg+1, oKnots.end());
74 
75  // merge coefficients
76  unsigned n= this->coefsSize();
77  index_t skip = continuous ? 1 : 0;
78  this->m_coefs.conservativeResize( n + other->coefsSize() -skip, gsEigen::NoChange ) ;
79 
80  this->m_coefs.block( n,0,other->coefsSize()-skip,other->geoDim() ) =
81  other->m_coefs.block( 1,0,other->coefsSize()-skip,other->geoDim() ) ;
82 
83  delete other;
84 }
85 
86 template<class T>
87 gsBSpline<T> gsBSpline<T>::segmentFromTo(T u0, T u1, T tolerance) const
88 {
89 
90  GISMO_ASSERT(domainStart()-tolerance < u0 && u0 < domainEnd()+tolerance,
91  "starting point "<< u0 <<" not in the knot vector");
92  GISMO_ASSERT(domainStart()-tolerance < u1 && u1 < domainEnd()+tolerance,
93  "end point "<< u1 <<" not in the knot vector");
94 
95  //First make a copy of the actual object, to allow const
96  gsBSpline<T> copy(*this);
97 
98  // Extract a reference to the knots, the basis and coefs of the copy
99  KnotVectorType & knots = copy.basis().knots();
100 
101  // some constants
102  const short_t p = basis().degree(); // degree
103  const index_t multStart = p + 1 - knots.multiplicity(u0); // multiplicity
104  const index_t multEnd = p + 1 - knots.multiplicity(u1); // multiplicity
105 
106  // insert the knot, such that its multiplicity is p+1
107  if (multStart>0)
108  copy.insertKnot(u0, 0, multStart);
109  if (multEnd>0)
110  copy.insertKnot(u1, 0, multEnd );
111 
112  gsMatrix<T>& coefs = copy.coefs();
113  const index_t tDim = coefs.cols();
114 
115  // Split the coefficients
116  // find the number of coefs left from u0
117  const index_t nL = knots.uFind(u0).firstAppearance();
118  // find the number of coefs left from u1
119  index_t nL2 = knots.uFind(u1).firstAppearance();
120  bool isEnd = math::abs(u1 - this->domainEnd()) < tolerance;
121 // if ( isEnd ) { nL2 += 1; } // Adjust for end parameter
122  if ( isEnd )
123  nL2 = copy.numCoefs(); // Adjust for end parameter
124 
125  // Prepare control points for new geometry
126  gsMatrix<T> coefRes = coefs.block(nL, 0, nL2-nL, tDim);
127 
128  // Prepare new knot vector
129  typename KnotVectorType::iterator itStart = knots.iFind(u0);
130  typename KnotVectorType::iterator itEnd = knots.iFind(u1) + (isEnd ? p + 1 : 0);
131  typename KnotVectorType::knotContainer matRes(itStart-p, itEnd+1);
132  KnotVectorType knotsRes(give(matRes), p);
133 
134  return gsBSpline<T>(Basis(give(knotsRes)), give(coefRes));
135 }
136 
137 template<class T>
139 {
140  gsMultiPatch<T> bezierSegments;
141 
142  gsBSpline<T> currentSegment(*this);
143  gsBSpline<T> leftPart;
144 
145  for (auto iter = this->knots().ubegin() + 1; iter != this->knots().uend() - 1; ++iter)
146  {
147  currentSegment.splitAt(*iter, leftPart, currentSegment, tolerance);
148  bezierSegments.addPatch(leftPart);
149  }
150 
151  bezierSegments.addPatch(currentSegment); // Add the last segment
152  return bezierSegments;
153 }
154 
155 template<class T>
156 std::vector<internal::gsCurveIntersectionResult<T>> gsBSpline<T>::intersect(const gsBSpline<T>& other,
157  T tolerance,
158  T curvatureTolerance) const
159 {
160  std::vector<internal::gsBoundingBoxPair<T>> hulls = internal::getPotentialIntersectionRanges<T>(*this, other, curvatureTolerance);
161 
162  std::vector<internal::gsCurveIntersectionResult<T>> results;
163  for (typename std::vector<internal::gsBoundingBoxPair<T>>::const_iterator hull = hulls.begin(); hull!=hulls.end(); hull++)
164  {
165  gsBSpline<T> crv1 = this->segmentFromTo(hull->b1.getRange().getMin(), hull->b1.getRange().getMax());
166  gsBSpline<T> crv2 = other.segmentFromTo(hull->b2.getRange().getMin(), hull->b2.getRange().getMax());
167 
168  internal::gsCurveCurveDistanceSystem<T> obj(crv1, crv2);
169  gsVector<T,2> uv;
170  uv(0) = 0.5 * (crv1.domainStart() + crv1.domainEnd());
171  uv(1) = 0.5 * (crv2.domainStart() + crv2.domainEnd());
172  T distance = obj.compute(uv, tolerance);
173 
174  if (distance < math::max( (T)1e-10, tolerance))
175  {
176  gsMatrix<T> uCrv1(1,1), uCrv2(1,1);
177  uCrv1(0,0) = uv(0);
178  uCrv2(0,0) = uv(1);
179  gsMatrix<T> pt = 0.5 * (crv1.eval(uCrv1) + crv2.eval(uCrv2));
180  internal::gsCurveIntersectionResult<T> result(uv(0), uv(1), pt);
181  results.push_back(result);
182  }
183  }
184 
185  return results;
186 }
187 
188 template<class T>
190 {
191  index_t coefsSize = m_coefs.rows();
192 
193  T len = (m_coefs.row(0)-m_coefs.row(coefsSize-1)).norm();
194  T total = 0.0;
195  for (index_t ipt = 0; ipt != coefsSize - 1; ++ipt)
196  {
197  T dist = (m_coefs.row(ipt) - m_coefs.row(ipt + 1)).norm();
198  total += dist;
199  }
200  return total / len;
201 }
202 
203 template<class T>
205 {
206  GISMO_UNUSED(dir);
207  if (i==0) return;
208  //if ( i==1)
209  //single knot insertion: Boehm's algorithm
210  //else
211  //knot with multiplicity: Oslo algorithm
212  if( this->basis().isPeriodic() )
213  {
214  int borderKnotMult = this->basis().borderKnotMult();
215  KnotVectorType & knots = this->knots();
216  unsigned deg = this->basis().degree();
217 
218  GISMO_ASSERT( knot != knots[deg] && knot != knots[knots.size() - deg - 1],
219  "You are trying to increase the multiplicity of the p+1st knot but the code is not ready for that.\n");
220 
221  // If we would be inserting to "passive" regions, we
222  // rather insert the knot into the mirrored part.
223  // Adjustment of the mirrored knots is then desirable.
224  if( knot < knots[deg - borderKnotMult + 1] )
225  {
226  knot += this->basis()._activeLength();
227  }
228  else if( knot > knots[knots.size() - deg + borderKnotMult - 2] )
229  {
230  knot -= this->basis()._activeLength();
231  }
232  // If necessary, we update the mirrored part of the knot vector.
233  if((knot < knots[2*deg + 1 - borderKnotMult]) || (knot >= knots[knots.size() - 2*deg - 2 + borderKnotMult]))
234  this->basis().enforceOuterKnotsPeriodic();
235 
236  // We copy some of the control points to pretend for a while
237  // that the basis is not periodic.
238 
239  //gsMatrix<T> trueCoefs = this->basis().perCoefs( this->coefs() );
240  gsBoehm( this->basis().knots(), this->coefs(), knot, i );
241  //this->coefs() = trueCoefs;
242  //this->coefs().conservativeResize( this->basis().size(), this->coefs().cols() );
243  }
244  else // non-periodic
245  gsBoehm( this->basis().knots(), this->coefs() , knot, i);
246 }
247 
248 template<class T>
250 {
251  insertKnot(knot,0,i);
252 }
253 
254 template<class T>
255 void gsBSpline<T>::splitAt(T u0, gsBSpline<T>& left, gsBSpline<T>& right, T tolerance) const
256 {
257  GISMO_ASSERT(domainStart()-tolerance < u0 && u0 < domainEnd()+tolerance,
258  "splitting point "<< u0 <<" not in the knot vector");
259 
260  left = segmentFromTo(this->domainStart(), u0, tolerance);
261  right = segmentFromTo(u0, this->domainEnd(), tolerance);
262 }
263 
264 template<class T>
265 bool gsBSpline<T>::isOn(gsMatrix<T> const &u, T tol) const
266 {
267  GISMO_ASSERT( u.cols() == 1, "Expecting single point.");
268  gsBSplineSolver<T> slv;
269  gsMatrix<T> e;
270 
271  for ( index_t k = 0; k != u.rows(); ++k)
272  {
273  std::vector<T> roots;
274  slv.allRoots(*this, roots, k, u(k,0) ) ;
275 
276  if( roots.size()!=0 )
277  {
278  gsAsMatrix<T> xx(roots);
279  this->eval_into( xx, e );
280 
281  //if( math::abs( e(!k,0)-u(!k,0) ) < tol )
282  for(index_t j=0; j!=e.cols(); j++)
283  if( ( e.col(j)-u ).norm() < tol )
284  return true;
285  }
286  }
287  return false;
288 }
289 
290 template<class T>
291 bool gsBSpline<T>::isPatchCorner(gsMatrix<T> const &v, T tol) const
292 {
293  return (( v - m_coefs.row(0) ).squaredNorm() < tol ||
294  ( v - m_coefs.bottomRows(1)).squaredNorm() < tol );
295 }
296 
297 template<class T>
299  gsVector<index_t,1> & curr,
300  T tol)
301 {
302  if ((v - m_coefs.row(0)).squaredNorm() < tol)
303  curr[0] = 0;
304  else if ((v - m_coefs.bottomRows(1)).squaredNorm() < tol)
305  curr[0] = m_coefs.rows()-1;
306  else
307  {
308  curr[0] = m_coefs.rows(); // invalidate result
309  gsWarn<<"Point "<< v <<" is not an corner of the patch. (Call isPatchCorner() first!).\n";
310  }
311 }
312 
313 
314 template<class T>
316 {
317  if ((v - m_coefs.row(0)).squaredNorm() < (T)(1e-3))
318  return;
319  else if ((v - m_coefs.bottomRows(1)).squaredNorm() < (T)(1e-3))
320  this->reverse();
321  else
322  gsWarn<<"Point "<< v <<" is not an endpoint of the curve.\n";
323 }
324 
325 template<class T>
327 {
328  if ((v - m_coefs.bottomRows(1)).squaredNorm() < (T)(1e-3))
329  return;
330  else if ((v - m_coefs.row(0)).squaredNorm() < (T)(1e-3))
331  this->reverse();
332  else
333  gsWarn<<"Point "<< v <<" is not an endpoint of the curve.\n";
334 }
335 
336 template <class T>
337 void gsBSpline<T>::swapDirections(const unsigned i, const unsigned j)
338 {
339  GISMO_UNUSED(i);
340  GISMO_UNUSED(j);
341  GISMO_ASSERT( static_cast<int>(i) == 0 && static_cast<int>(j) == 0,
342  "Invalid basis components "<<i<<" and "<<j<<" requested" );
343 }
344 
345 
346 template<class T>
348 {
349  GISMO_UNUSED(dir);
350  GISMO_ASSERT( (dir == -1) || (dir == 0),
351  "Invalid basis component "<< dir <<" requested for degree elevation" );
352 
353  bspline::degreeElevateBSpline(this->basis(), this->m_coefs, i);
354 }
355 
356 namespace internal
357 {
358 
360 template<class T>
361 class gsXml< gsBSpline<T> >
362 {
363 private:
364  gsXml() { }
365 public:
366  GSXML_COMMON_FUNCTIONS(gsBSpline<T>);
367  static std::string tag () { return "Geometry"; }
368  static std::string type () { return "BSpline"; }
369 
370  static gsBSpline<T> * get (gsXmlNode * node)
371  {
372  return getGeometryFromXml< gsBSpline<T> >(node);
373  }
374 
375  static gsXmlNode * put (const gsBSpline<T> & obj,
376  gsXmlTree & data )
377  {
378  return putGeometryToXml< gsBSpline<T> >(obj,data);
379  }
380 };
381 
382 
383 }// namespace internal
384 
385 } // namespace gismo
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
index_t addPatch(typename gsGeometry< T >::uPtr g)
Add a patch from a gsGeometry&lt;T&gt;::uPtr.
Definition: gsMultiPatch.hpp:210
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
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
T pseudoCurvature() const
Definition: gsBSpline.hpp:189
bool gsAllCloseAbsolute(const matrix_t1 &a, const matrix_t2 &b, const typename matrix_t1::Scalar &tol)
tests if the difference between two matrices is bounded by tol in norm
Definition: gsMath.h:465
T distance(gsMatrix< T > const &A, gsMatrix< T > const &B, index_t i=0, index_t j=0, bool cols=false)
compute a distance between the point number in the set and the point number &lt;j&gt; in the set ; by def...
Creates a mapped object or data pointer to a matrix without copying data.
Definition: gsLinearAlgebra.h:126
Implementation of B Spline Curve/Curve intersection.
#define short_t
Definition: gsConfig.h:35
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
S give(S &x)
Definition: gsMemory.h:266
gsMatrix< T > eval(const gsMatrix< T > &u) const
Evaluate the function,.
Definition: gsFunctionSet.hpp:120
#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
Provides implementation of generic XML functions.
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
void degreeElevateBSpline(Basis_t &basis, gsMatrix< typename Basis_t::Scalar_t > &coefs, short_t m)
Increase the degree of a 1D B-spline from degree p to degree p + m.
Definition: gsBSplineAlgorithms.h:224
void insertKnot(T knot, index_t i=1)
Definition: gsBSpline.hpp:249
Implementation of common algorithms for B-splines.
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition: gsVector.h:35
#define gsWarn
Definition: gsDebug.h:50
Provides declaration of the MultiPatch class.
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition: gsMultiPatch.h:33
std::vector< internal::gsCurveIntersectionResult< T > > intersect(const gsBSpline< T > &other, T tolerance=1e-5, T curvatureTolerance=1+1e-6) const
Definition: gsBSpline.hpp:156
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
gsMultiPatch< T > toBezier(T tolerance=1e-15) const
Definition: gsBSpline.hpp:138
#define GISMO_UNUSED(x)
Definition: gsDebug.h:112
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
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
Provides declaration of input/output XML utilities struct.
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
void copy(T begin, T end, U *result)
Small wrapper for std::copy mimicking std::copy for a raw pointer destination, copies n positions sta...
Definition: gsMemory.h:391