G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsBSplineSolver.hpp
Go to the documentation of this file.
1
15#pragma once
16
17# include <gsNurbs/gsBSpline.h>
18
19#include <numeric>
20
21namespace gismo {
22
23template<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
55template<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
130enum Position
131{
132 // new scheme
133 greater= 1,
134 smaller=-greater,
135 equal = 1<<5,
136 undef = 0
137};
138
139template <typename T>
140Position 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
151template <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
bool nextRoot()
Next root (requires that first root has been called before)
Definition gsBSplineSolver.hpp:56
int insertKnot(int mu)
Definition gsBSplineSolver.hpp:24
A B-spline function of one argument, with arbitrary target dimension.
Definition gsBSpline.h:51
void insertKnot(T knot, index_t i=1)
Definition gsBSpline.hpp:249
KnotVectorType & knots(const int i=0)
Returns a reference to the knot vector.
Definition gsBSpline.h:170
short_t degree(short_t i=0) const
Returns the degree of the B-spline.
Definition gsBSpline.h:186
gsMatrix< T > eval(const gsMatrix< T > &u) const
Evaluate the function,.
Definition gsFunctionSet.hpp:120
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
index_t coefsSize() const
Return the number of coefficients (control points)
Definition gsGeometry.h:371
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
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
Represents a B-spline curve/function with one parameter.
#define index_t
Definition gsConfig.h:32
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
The G+Smo namespace, containing all definitions for the library.