ViSP  2.8.0
vpBSpline.cpp
1 /****************************************************************************
2  *
3  * $Id: vpBSpline.cpp 4303 2013-07-04 14:14:00Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * This class implements the B-Spline
36  *
37  * Authors:
38  * Nicolas Melchior
39  *
40  *****************************************************************************/
41 
42 #include <visp/vpBSpline.h>
43 #include <visp/vpDebug.h>
44 
52 {
53  p = 3; //By default : clubic spline
54 }
55 
61 {
62  controlPoints = bspline.controlPoints;
63  knots = bspline.knots;
64  p = bspline.p;
65  crossingPoints = bspline.crossingPoints;
66 }
71 {
72 }
73 
88 unsigned int
89 vpBSpline::findSpan(double l_u, unsigned int l_p, std::vector<double> &l_knots)
90 {
91  unsigned int m = (unsigned int)l_knots.size()-1;
92 
93  if(l_u > l_knots.back())
94  {
95  //vpTRACE("l_u higher than the maximum value in the knot vector : %lf",l_u);
96  return((unsigned int)(m-l_p-1));
97  }
98 
99  //if (l_u == l_knots.back())
100  if (std::fabs(l_u - l_knots.back()) <= std::fabs(vpMath::maximum(l_u, l_knots.back())) * std::numeric_limits<double>::epsilon())
101  return((unsigned int)(m-l_p-1));
102 
103  double low = l_p;
104  double high = m-l_p;
105  double middle = (low+high)/2.0;
106 
107  while (l_u < l_knots[(unsigned int)vpMath::round(middle)] || l_u >= l_knots[(unsigned int)vpMath::round(middle+1)])
108  {
109  if(l_u < l_knots[(unsigned int)vpMath::round(middle)]) high = middle;
110  else low = middle;
111  middle = (low+high)/2.0;
112  }
113 
114  return (unsigned int)middle;
115 }
116 
117 
130 unsigned int
132 {
133  return findSpan( u, p, knots);
134 }
135 
136 
149 vpBasisFunction* vpBSpline::computeBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, std::vector<double> &l_knots)
150 {
151  vpBasisFunction* N = new vpBasisFunction[l_p+1];
152 
153  N[0].value = 1.0;
154 
155  double *left = new double[l_p+1];
156  double *right = new double[l_p+1];
157  double saved = 0.0;
158  double temp = 0.0;
159 
160  for(unsigned int j = 1; j <= l_p; j++)
161  {
162  left[j] = l_u - l_knots[l_i+1-j];
163  right[j] = l_knots[l_i+j] - l_u;
164  saved = 0.0;
165 
166  for (unsigned int r = 0; r < j; r++)
167  {
168  temp = N[r].value / (right[r+1]+left[j-r]);
169  N[r].value = saved +right[r+1]*temp;
170  saved = left[j-r]*temp;
171  }
172  N[j].value = saved;
173  }
174  for(unsigned int j = 0; j < l_p+1; j++)
175  {
176  N[j].i = l_i-l_p+j;
177  N[j].p = l_p;
178  N[j].u = l_u;
179  N[j].k = 0;
180  }
181 
182  delete[] left;
183  delete[] right;
184 
185  return N;
186 }
187 
188 
200 vpBasisFunction* vpBSpline::computeBasisFuns(double u)
201 {
202  unsigned int i = findSpan(u);
203  return computeBasisFuns(u, i, p ,knots);
204 }
205 
206 
230 vpBasisFunction** vpBSpline::computeDersBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, std::vector<double> &l_knots)
231 {
232  vpBasisFunction** N;
233  N = new vpBasisFunction*[l_der+1];
234  for(unsigned int j = 0; j <= l_der; j++)
235  N[j] = new vpBasisFunction[l_p+1];
236 
237  vpMatrix a(2,l_p+1);
238  vpMatrix ndu(l_p+1,l_p+1);
239  ndu[0][0] = 1.0;
240 
241  double *left = new double[l_p+1];
242  double *right = new double[l_p+1];
243  double saved = 0.0;
244  double temp = 0.0;
245 
246  for(unsigned int j = 1; j <= l_p; j++)
247  {
248  left[j] = l_u - l_knots[l_i+1-j];
249  right[j] = l_knots[l_i+j] - l_u;
250  saved = 0.0;
251 
252  for (unsigned int r = 0; r < j; r++)
253  {
254  ndu[j][r] = right[r+1]+left[j-r];
255  temp = ndu[r][j-1]/ndu[j][r];
256  ndu[r][j] = saved + right[r+1]*temp;
257  saved = left[j-r]*temp;
258  }
259  ndu[j][j] = saved;
260  }
261 
262  for(unsigned int j = 0; j <= l_p; j++)
263  {
264  N[0][j].value = ndu[j][l_p];
265  N[0][j].i = l_i-l_p+j;
266  N[0][j].p = l_p;
267  N[0][j].u = l_u;
268  N[0][j].k = 0;
269  }
270 
271  if( l_der > l_p)
272  {
273  vpTRACE("l_der must be under or equal to l_p");
274  l_der = l_p;
275  }
276 
277  unsigned int s1,s2;
278  double d;
279  int rk;
280  unsigned int pk;
281  unsigned int j1,j2;
282 
283  for (unsigned int r = 0; r <= l_p; r++)
284  {
285  s1 = 0;
286  s2 = 1;
287  a[0][0] = 1.0;
288  for(unsigned int k = 1; k <= l_der; k++)
289  {
290  d = 0.0;
291  rk = (int)(r-k);
292  pk = l_p-k;
293  if(r >= k)
294  {
295  a[s2][0] = a[s1][0]/ndu[pk+1][rk];
296  d = a[s2][0]*ndu[(unsigned int)rk][pk];
297  }
298 
299  if(rk >= -1)
300  j1 = 1;
301  else
302  j1 = (unsigned int)(-rk);
303 
304  if(r-1 <= pk)
305  j2 = k-1;
306  else
307  j2 = l_p-r;
308 
309  for(unsigned int j =j1; j<= j2; j++)
310  {
311  a[s2][j] = (a[s1][j]-a[s1][j-1])/ndu[pk+1][(unsigned int)rk+j];
312  d += a[s2][j]*ndu[(unsigned int)rk+j][pk];
313  }
314 
315  if(r <= pk)
316  {
317  a[s2][k] = -a[s1][k-1]/ndu[pk+1][r];
318  d += a[s2][k]*ndu[r][pk];
319  }
320  N[k][r].value = d;
321  N[k][r].i = l_i-l_p+r;
322  N[k][r].p = l_p;
323  N[k][r].u = l_u;
324  N[k][r].k = k;
325 
326  s1 = (s1+1)%2;
327  s2 = (s2+1)%2;
328  }
329  }
330 
331  double r = l_p;
332  for ( unsigned int k = 1; k <= l_der; k++ )
333  {
334  for (unsigned int j = 0; j <= l_p; j++)
335  N[k][j].value *= r;
336  r *= (l_p-k);
337  }
338 
339  delete[] left;
340  delete[] right;
341 
342  return N;
343 }
344 
345 
366 vpBasisFunction** vpBSpline::computeDersBasisFuns(double u, unsigned int der)
367 {
368  unsigned int i = findSpan(u);
369  return computeDersBasisFuns(u, i, p , der, knots);
370 }
371 
372 
384 vpImagePoint vpBSpline::computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, std::vector<double> &l_knots, std::vector<vpImagePoint> &l_controlPoints)
385 {
386  vpBasisFunction* N = computeBasisFuns(l_u, l_i, l_p, l_knots);
387  vpImagePoint pt;
388 
389  double ic = 0;
390  double jc = 0;
391  for(unsigned int j = 0; j <= l_p; j++)
392  {
393  ic = ic + N[j].value * (l_controlPoints[l_i-l_p+j]).get_i();
394  jc = jc + N[j].value * (l_controlPoints[l_i-l_p+j]).get_j();
395  }
396 
397  pt.set_i(ic);
398  pt.set_j(jc);
399 
400  delete[] N;
401 
402  return pt;
403 }
404 
405 
414 {
415  vpBasisFunction* N = computeBasisFuns(u);
416  vpImagePoint pt;
417 
418  double ic = 0;
419  double jc = 0;
420  for(unsigned int j = 0; j <= p; j++)
421  {
422  ic = ic + N[j].value * (controlPoints[N[0].i+j]).get_i();
423  jc = jc + N[j].value * (controlPoints[N[0].i+j]).get_j();
424  }
425 
426  pt.set_i(ic);
427  pt.set_j(jc);
428 
429  delete[] N;
430 
431  return pt;
432 }
433 
434 
453 vpImagePoint* vpBSpline::computeCurveDers(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, std::vector<double> &l_knots, std::vector<vpImagePoint> &l_controlPoints)
454 {
455  vpImagePoint *derivate = new vpImagePoint[l_der+1];
456  vpBasisFunction** N;
457  N = computeDersBasisFuns(l_u, l_i, l_p, l_der, l_knots);
458 
459  unsigned int du;
460  if (l_p < l_der)
461  {
462  vpTRACE("l_der must be under or equal to l_p");
463  du = l_p;
464  }
465  else du = l_der;
466 
467  for(unsigned int k = 0; k <= du; k++)
468  {
469  derivate[k].set_ij(0.0,0.0);
470  for(unsigned int j = 0; j<= l_p; j++)
471  {
472  derivate[k].set_i( derivate[k].get_i() + N[k][j].value*(l_controlPoints[l_i-l_p+j]).get_i());
473  derivate[k].set_j( derivate[k].get_j() + N[k][j].value*(l_controlPoints[l_i-l_p+j]).get_j());
474  }
475  }
476 
477 
478  for(unsigned int j = 0; j <= l_der; j++)
479  delete[] N[j];
480  delete[] N;
481 
482 
483  return derivate;
484 }
485 
486 
501 vpImagePoint* vpBSpline::computeCurveDers(double u, unsigned int der)
502 {
503  vpImagePoint *derivate = new vpImagePoint[der+1];
504  vpBasisFunction** N;
505  N = computeDersBasisFuns(u, der);
506 
507  unsigned int du;
508  if (p < der)
509  {
510  vpTRACE("der must be under or equal to p");
511  du = p;
512  }
513  else du = der;
514 
515  for(unsigned int k = 0; k <= du; k++)
516  {
517  derivate[k].set_ij(0.0,0.0);
518  for(unsigned int j = 0; j<= p; j++)
519  {
520  derivate[k].set_i( derivate[k].get_i() + N[k][j].value*(controlPoints[N[0][0].i-p+j]).get_i());
521  derivate[k].set_j( derivate[k].get_j() + N[k][j].value*(controlPoints[N[0][0].i-p+j]).get_j());
522  }
523  }
524 
525  for(unsigned int j = 0; j <= der; j++)
526  delete[] N[j];
527  delete[] N;
528 
529  return derivate;
530 }
void set_j(const double j)
Definition: vpImagePoint.h:156
static vpImagePoint * computeCurveDers(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints)
Definition: vpBSpline.cpp:453
Definition of the vpMatrix class.
Definition: vpMatrix.h:96
virtual ~vpBSpline()
Definition: vpBSpline.cpp:70
#define vpTRACE
Definition: vpDebug.h:401
void set_i(const double i)
Definition: vpImagePoint.h:145
static int round(const double x)
Definition: vpMath.h:228
static vpBasisFunction ** computeDersBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, std::vector< double > &l_knots)
Definition: vpBSpline.cpp:230
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:137
static unsigned int findSpan(double l_u, unsigned int l_p, std::vector< double > &l_knots)
Definition: vpBSpline.cpp:89
void set_ij(const double i, const double j)
Definition: vpImagePoint.h:167
static vpBasisFunction * computeBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, std::vector< double > &l_knots)
Definition: vpBSpline.cpp:149
Class that provides tools to compute and manipulate a B-Spline curve.
Definition: vpBSpline.h:109
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
static vpImagePoint computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints)
Definition: vpBSpline.cpp:384