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