G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsBSplineSolver.hpp
Go to the documentation of this file.
1 
15 #pragma once
16 
17 # include <gsNurbs/gsBSpline.h>
18 
19 #include <numeric>
20 
21 namespace gismo {
22 
23 template<class T>
25 {
26  // find span (in case mu is not tight)
27  mu = math::max(mu,m_d);
28 
29  while ( x>=m_t[mu+1]) mu++;
30 
31  // make room for one coefficient at position mu
32  m_c.insert(m_c.begin()+mu,0);
33  //for ( int i=m_n; i>mu; i--) m_c[i] = m_c[i-1];
34 
35  // Compute new coefficients
36  for ( int i=mu; i>=mu-m_d+1; i--)
37  {
38  const T alpha = (x-m_t[i])/(m_t[i+m_d]-m_t[i]);
39  m_c[i] = (1.0-alpha) * m_c[i-1] + alpha * m_c[i];
40  }
41 
42  // set last knot
43  m_t[m_n+m_d] = m_t[m_n+m_d-1];
44 
45  //insert the knot in the knot sequence
46  m_t.insert(m_t.begin()+mu+1,x);
47  // for ( int i=m_n; i>mu+1; --i)
48  // m_t[i] = m_t[i-1];
49  // m_t[mu+1] = x;
50 
51  m_n++;
52  return mu;
53 }
54 
55 template<class T>
57 {
58  // Do until maxn knots are inserted
59  while ( m_n < maxn )
60  {
61  // Find sign change
62  while( m_k<m_n && (m_c[m_k-1]*m_c[m_k] > 0) )
63  {
64  ++m_k;
65  //gsLog<<"m_c[m_k]= "<< m_c[m_k] <<" ( m_k="<<m_k<<")\n";
66  }
67 
68  // No sign change ?
69  if ( m_k >= m_n )
70  return false;
71  //gsLog<<"Sign change at "<< m_c[m_k]<<", "<< m_c[m_k+1] <<" (position "<<m_k<<")\n";
72 
73  // Interval converged ?
74  const T diff = m_t[m_k+m_d]-m_t[m_k];
75  if (diff<eps)
76  {
77  x = m_t[m_k];// root found
78  //gsDebug <<"diff converged: Root found at "<< m_k<<", val="<< x <<"m_n="<<m_n <<"\n";
79  break;
80  }
81 
82  // Horizontal alignment ?
83  const T cdiff = m_c[m_k-1]-m_c[m_k];
84  if (math::abs(cdiff)<eps)
85  {
86  ++m_k;
87  continue;
88  }
89 
90  // compute line slope
91  const T lambda = m_c[m_k-1] / cdiff ;
92 
93  // compute intersection
94  x = (std::accumulate(m_t.begin()+m_k, m_t.begin()+m_k+m_d, (T)(0.0) )
95  + lambda*diff ) / (T)(m_d);
96  //x = ( m_t.segment(m_k, m_d).sum() + lambda*diff ) / (T)(m_d);
97 
98  // Stopping criterion
99  const T e = math::max(x, m_t[m_k+m_d-1]) - math::min(x, m_t[m_k+1] );
100  if (e < eps)
101  {
102  //gsDebug <<"eps: Root found after knot "<< m_k <<" is "<<m_t[m_k]<<", val="<< x <<"\n";
103  break;
104  }
105 
106  insertKnot(m_k);
107  //gsLog<<"Inserted knot, m_k="<< m_k <<", m_t[m_k]="<<m_t[m_k]<<", m_n="<< m_n<<"\n";
108 
109  } // end for
110 
111 
112  //gsLog<<"Loop finished with "<< x <<" m_k="<<m_k<<", m_c[m_k]="<<m_c[m_k]<<", m_t[m_k]="<<m_t[m_k]<< ", m_n="<< m_n<<"\n";
113 
114  if ( m_n>=maxn )
115  {
116  gsWarn<<"gsBSplineRoot: Maximum number of knots reached: "<< m_n << "\n";
117  //gsDebug<< "m_c:\n"<< m_c.transpose()<<"\n";
118  //gsDebug<< "m_t:\n"<< m_t.transpose()<<"\n";
119  return false;
120  }
121 
122  m_k++; // next root
123 
124  // buggy: while ( m_k<m_n && math::fabs( m_t[m_k]-x)<eps ) m_k++;
125 
126  //gsDebug<<"next m_k="<< m_k <<" is "<< m_t[m_k]<<"\n";
127  return true;
128 }
129 
130 enum Position
131 {
132  // new scheme
133  greater= 1,
134  smaller=-greater,
135  equal = 1<<5,
136  undef = 0
137 };
138 
139 template <typename T>
140 Position relativePosition (const T pos, const T ref, const T tol)
141 {
142  if ( pos < ref-tol )
143  return smaller;
144  if ( pos > ref+tol )
145  return greater;
146  if ( pos <= ref+tol && pos >= ref-tol)
147  return equal;
148  return undef;
149 }
150 
151 template <typename T>
153  const gsBSpline<T> &curve,
154  const gsVector<T> &normal,
155  T reference,
156  T tolerance,
157  std::vector<Root<T> > &roots
158  )
159 {
160  // argument check
161  GISMO_ASSERT( curve.coefDim() == normal.rows(),
162  "cannot intersect a curve in R^"<< curve.coefDim()<<" with a hyperplane in R^"<< normal.rows() );
163  if ( !math::isfinite(reference + normal.sum()) )
164  {
165  gsWarn<<"No intersection reportet between curve and invalid hyperplane."<<std::endl;
166  }
167 
168  // environment description
169  const int deg = curve.degree();
170  const T tol = tolerance;
171  const T ref = reference;
172 
173  // internal copy of the curve used for knot insertion
174  gsBSpline<T> crv(curve);
175 
176  // position status
177  Position curP = relativePosition(crv.coef(0).dot(normal), ref, tol) ; // current Position
178  if ( curP == undef )
179  {
180  gsWarn<<__FUNCTION__<<": first coefficient of curve is NAN, exit without results."<<std::endl;
181  return 0;
182  }
183  Position newP = undef;
184  Position oldP = undef;
185  bool is_odd = true;
186 
187  // knots in the parameter domain
188  T oldK = NAN; // last knot inserted
189  T newK = NAN; // knot to be insert
190 
191  // counters
192  int curC = 1; // current coefficient (Control Point)
193  int lstC = 0; // coefficient in which the position became the current one
194  int intB = 0; // we insert a new knot between the Greville abscissas of intB and curC
195  int newK_rep = 0; // number of time we inserted the same knot
196  unsigned rootCount = 0; // total number of roots found
197 
198  for ( ; (index_t)curC<crv.coefsSize(); ++curC )
199  {
200  newP = relativePosition(crv.coef(curC).dot(normal), ref, tol); // current Position
201  if ( newP == undef )
202  {
203  gsWarn<<__FUNCTION__<<": stopping the search for intersection because the curve contains nan coefficients"<<std::endl;
204  return rootCount;
205  }
206  if(curP==newP)
207  continue;
208 
209  switch (curP)
210  {
211  case greater:
212  case smaller:
213  if (curP+newP!=0)
214  {
215  // from one side of the hyperplane to inside the hyperplane
216  // we need to scan till the end of the intersection to determine
217  // the type so we only change the state
218  oldP=curP;
219  curP=newP;
220  lstC=curC;
221  continue;
222  }
223  // otherwise follow the code to knot insertion
224  is_odd=true;
225  intB=curC-1;
226  break;
227  case equal:
228  if (curC-lstC > deg) // interval in hyperplane
229  {
230  is_odd=(newP!=oldP);
231  gsMatrix<T> params;
232  params.resize(1,2);
233  params(0,0) = crv.knots()[lstC+deg];
234  params(0,1) = crv.knots()[curC];
235  gsMatrix<T> points=crv.eval(params);
236  roots.push_back(Root<T>(is_odd, params(0,0),params(0,1),points.col(0),points.col(1)));
237  ++rootCount;
238  curP=newP;
239  newK_rep=0;
240  continue;
241  }
242  else if ( (curC-lstC) >= deg+1-(int)crv.knots().multiplicityIndex(curC)) // interpolatory point in hyperplane
243  {
244  is_odd=(newP!=oldP);
245  gsMatrix<T> params;
246  params.resize(1,1);
247  params(0,0) = crv.knots()[curC];
248  gsMatrix<T> points=crv.eval(params);
249  roots.push_back(Root<T>(is_odd, params(0,0),points.col(0)));
250  ++rootCount;
251  curP=newP;
252  newK_rep=0;
253  continue;
254  }
255  else if (newP==oldP)
256  {
257  curP=newP;
258  continue;
259  }
260  else
261  {
262  is_odd = true;
263  intB=math::max(0,lstC-1);
264  }
265  break;
266  default:
267  GISMO_ASSERT(false, __FUNCTION__<<"The impossible happened! Check for B..S!!" );
268  }
269  const T grevB = crv.knots().greville(intB);
270  const T grevE = crv.knots().greville(curC);
271  const T coeffB = crv.coef(curC).dot(normal)-ref;
272  const T coeffE = ref-crv.coef(intB).dot(normal);
273  const T denom = (crv.coef(curC)-crv.coef(intB)).dot(normal);
274  newK = coeffB*(grevB/denom)+coeffE*(grevE/denom);
275  // in rare but real cases we go out of the interval due to numerical approximation
276  newK = math::max(newK, curve.knots().first());
277  newK = math::min(newK, curve.knots().last());
278 
279  if ( math::abs(newK-oldK) < tol )
280  {
281  gsMatrix<T> point=crv.eval(gsMatrix<T>::Constant(1,1,newK));
282  if (math::abs(point.col(0).dot(normal)-ref)<tol)
283  {
284  roots.push_back(Root<T>(is_odd, newK,point.col(0)));
285  ++rootCount;
286  curP=newP;
287  oldK=NAN;
288  lstC=curC;
289  newK_rep=0;
290  continue;
291  }
292  if (newK==oldK) { newK_rep+=1; }
293  // if we inserted the same knot degre times and still do not
294  // satisfy the requirements then fallback to bisection
295  // as this could be caused by approximations in the computation of newK
296  if (newK_rep>=deg) newK=(grevB+grevE)/(T)(2);
297  // if the newK equals the previously added knot anyway then we
298  // resolved the position of the zero up to numerical precision
299  // in the domain, add the zero and warn that the image is outside the
300  // the hyperplane.
301  if (newK==oldK)
302  {
303  gsWarn<< __FUNCTION__<<": intersection does not satisfy required tolerance with knot insertion up to numerical precision\n";
304  roots.push_back(Root<T>(is_odd, newK,point.col(0)));
305  ++rootCount;
306  curP=newP;
307  oldK=NAN;
308  lstC=curC;
309  newK_rep=0;
310  continue;
311  }
312  }
313  crv.insertKnot(newK);
314  curC = math::max(math::max(curC-deg, lstC-1),0); // incremented by one on end of loop
315  curP = relativePosition(crv.coef(curC).dot(normal), ref, tol);
316  oldK = newK;
317  }
318  // intersections at the end of the curve
319  if(curP==equal)
320  {
321  if (curC-lstC > deg) // interval in hyperplane
322  {
323  gsMatrix<T> params;
324  params.resize(1,2);
325  params(0,0) = crv.knots()[lstC+deg];
326  params(0,1) = crv.knots()[curC];
327  gsMatrix<T> points=crv.eval(params);
328  roots.push_back(Root<T>(true, params(0,0),params(0,1),points.col(0),points.col(1)));
329  ++rootCount;
330  }
331  else
332  {
333  gsMatrix<T> params;
334  params.resize(1,1);
335  params(0,0) = crv.knots()[curC];
336  gsMatrix<T> points=crv.eval(params);
337  roots.push_back(Root<T>(true, params(0,0),points.col(0)));
338  ++rootCount;
339  }
340  }
341  return rootCount;
342 }
343 
344 } //namespace gismo
gsMatrix< T >::RowXpr coef(index_t i)
Returns the i-th coefficient of the geometry as a row expression.
Definition: gsGeometry.h:346
short_t coefDim() const
Dimension n of the coefficients (control points)
Definition: gsGeometry.h:289
bool nextRoot()
Next root (requires that first root has been called before)
Definition: gsBSplineSolver.hpp:56
gsMatrix< T > eval(const gsMatrix< T > &u) const
Evaluate the function,.
Definition: gsFunctionSet.hpp:120
#define index_t
Definition: gsConfig.h:32
unsigned findHyperPlaneIntersections(const gsBSpline< T > &curve, const gsVector< T > &normal, T reference, T tolerance, std::vector< Root< T > > &roots)
find intersections of a BSpline curve with an hyperplane
Definition: gsBSplineSolver.hpp:152
index_t coefsSize() const
Return the number of coefficients (control points)
Definition: gsGeometry.h:371
#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 insertKnot(T knot, index_t i=1)
Definition: gsBSpline.hpp:249
#define gsWarn
Definition: gsDebug.h:50
bool isfinite(const gsEigen::MatrixBase< Derived > &x)
Check if all the entires if the matrix x are not INF (infinite)
Definition: gsLinearAlgebra.h:109
KnotVectorType & knots(const int i=0)
Returns a reference to the knot vector.
Definition: gsBSpline.h:170
Represents a B-spline curve/function with one parameter.
int insertKnot(int mu)
Definition: gsBSplineSolver.hpp:24
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4488
short_t degree(short_t i=0) const
Returns the degree of the B-spline.
Definition: gsBSpline.h:186