Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
vpNurbs.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
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 https://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 Non Uniform Rational B-Spline (NURBS)
32  */
33 
34 #include <cmath> // std::fabs
35 #include <limits> // numeric_limits
36 #include <visp3/core/vpColVector.h>
37 #include <visp3/core/vpDebug.h>
38 #include <visp3/me/vpNurbs.h>
39 
41 /*
42  Compute the distance d = |Pw1-Pw2|
43 */
44 inline double distance(const vpImagePoint &iP1, double w1, const vpImagePoint &iP2, double w2)
45 {
46  double distancei = iP1.get_i() - iP2.get_i();
47  double distancej = iP1.get_j() - iP2.get_j();
48  double distancew = w1 - w2;
49  return sqrt(vpMath::sqr(distancei) + vpMath::sqr(distancej) + vpMath::sqr(distancew));
50 }
51 
52 vpNurbs::vpNurbs() : weights() { p = 3; }
53 
54 vpNurbs::vpNurbs(const vpNurbs &nurbs) : vpBSpline(nurbs), weights(nurbs.weights) { }
55 
56 vpImagePoint vpNurbs::computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, std::vector<double> &l_knots,
57  std::vector<vpImagePoint> &l_controlPoints, std::vector<double> &l_weights)
58 {
59  vpBasisFunction *N = nullptr;
60  N = computeBasisFuns(l_u, l_i, l_p, l_knots);
61  vpImagePoint pt;
62 
63  double ic = 0;
64  double jc = 0;
65  double wc = 0;
66  for (unsigned int j = 0; j <= l_p; j++) {
67  ic = ic + N[j].value * (l_controlPoints[l_i - l_p + j]).get_i() * l_weights[l_i - l_p + j];
68  jc = jc + N[j].value * (l_controlPoints[l_i - l_p + j]).get_j() * l_weights[l_i - l_p + j];
69  wc = wc + N[j].value * l_weights[l_i - l_p + j];
70  }
71 
72  pt.set_i(ic / wc);
73  pt.set_j(jc / wc);
74 
75  if (N != nullptr)
76  delete[] N;
77 
78  return pt;
79 }
80 
82 {
83  vpBasisFunction *N = nullptr;
84  N = computeBasisFuns(u);
85  vpImagePoint pt;
86 
87  double ic = 0;
88  double jc = 0;
89  double wc = 0;
90  for (unsigned int j = 0; j <= p; j++) {
91  ic = ic + N[j].value * (controlPoints[N[0].i + j]).get_i() * weights[N[0].i + j]; // N[0].i = findSpan(u)-p
92  jc = jc + N[j].value * (controlPoints[N[0].i + j]).get_j() * weights[N[0].i + j];
93  wc = wc + N[j].value * weights[N[0].i + j];
94  }
95 
96  pt.set_i(ic / wc);
97  pt.set_j(jc / wc);
98 
99  if (N != nullptr)
100  delete[] N;
101 
102  return pt;
103 }
104 
105 vpMatrix vpNurbs::computeCurveDers(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der,
106  std::vector<double> &l_knots, std::vector<vpImagePoint> &l_controlPoints,
107  std::vector<double> &l_weights)
108 {
109  vpMatrix derivate(l_der + 1, 3);
110  vpBasisFunction **N = nullptr;
111  N = computeDersBasisFuns(l_u, l_i, l_p, l_der, l_knots);
112 
113  for (unsigned int k = 0; k <= l_der; k++) {
114  derivate[k][0] = 0.0;
115  derivate[k][1] = 0.0;
116  derivate[k][2] = 0.0;
117 
118  for (unsigned int j = 0; j <= l_p; j++) {
119  derivate[k][0] = derivate[k][0] + N[k][j].value * (l_controlPoints[l_i - l_p + j]).get_i();
120  derivate[k][1] = derivate[k][1] + N[k][j].value * (l_controlPoints[l_i - l_p + j]).get_j();
121  derivate[k][2] = derivate[k][2] + N[k][j].value * (l_weights[l_i - l_p + j]);
122  }
123  }
124 
125  if (N != nullptr) {
126  for (unsigned int i = 0; i <= l_der; i++)
127  delete[] N[i];
128  delete[] N;
129  }
130  return derivate;
131 }
132 
133 vpMatrix vpNurbs::computeCurveDers(double u, unsigned int der)
134 {
135  vpMatrix derivate(der + 1, 3);
136  vpBasisFunction **N = nullptr;
137  N = computeDersBasisFuns(u, der);
138 
139  for (unsigned int k = 0; k <= der; k++) {
140  derivate[k][0] = 0.0;
141  derivate[k][1] = 0.0;
142  derivate[k][2] = 0.0;
143  for (unsigned int j = 0; j <= p; j++) {
144  derivate[k][0] = derivate[k][0] + N[k][j].value * (controlPoints[N[0][0].i - p + j]).get_i();
145  derivate[k][1] = derivate[k][1] + N[k][j].value * (controlPoints[N[0][0].i - p + j]).get_j();
146  derivate[k][2] = derivate[k][2] + N[k][j].value * (weights[N[0][0].i - p + j]);
147  }
148  }
149 
150  if (N != nullptr)
151  delete[] N;
152 
153  return derivate;
154 }
155 
156 vpImagePoint *vpNurbs::computeCurveDersPoint(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der,
157  std::vector<double> &l_knots, std::vector<vpImagePoint> &l_controlPoints,
158  std::vector<double> &l_weights)
159 {
160  std::vector<vpImagePoint> A;
161  vpImagePoint pt;
162  for (unsigned int j = 0; j < l_controlPoints.size(); j++) {
163  pt = l_controlPoints[j];
164  pt.set_i(pt.get_i() * l_weights[j]);
165  pt.set_j(pt.get_j() * l_weights[j]);
166  A.push_back(pt);
167  }
168 
169  vpMatrix Awders = computeCurveDers(l_u, l_i, l_p, l_der, l_knots, A, l_weights);
170 
171  vpImagePoint *CK = new vpImagePoint[l_der + 1];
172 
173  for (unsigned int k = 0; k <= l_der; k++) {
174  double ic = Awders[k][0];
175  double jc = Awders[k][1];
176  for (unsigned int j = 1; j <= k; j++) {
177  double tmpComb = static_cast<double>(vpMath::comb(k, j));
178  ic = ic - tmpComb * Awders[k][2] * (CK[k - j].get_i());
179  jc = jc - tmpComb * Awders[j][2] * (CK[k - j].get_j());
180  }
181  CK[k].set_ij(ic / Awders[0][2], jc / Awders[0][2]);
182  }
183  return CK;
184 }
185 
186 
187 vpImagePoint *vpNurbs::computeCurveDersPoint(double u, unsigned int der)
188 {
189  unsigned int i = findSpan(u);
190  return computeCurveDersPoint(u, i, p, der, knots, controlPoints, weights);
191 }
192 
193 
194 void vpNurbs::curveKnotIns(double l_u, unsigned int l_k, unsigned int l_s, unsigned int l_r, unsigned int l_p,
195  std::vector<double> &l_knots, std::vector<vpImagePoint> &l_controlPoints,
196  std::vector<double> &l_weights)
197 {
198  vpMatrix Rw(l_p + 1, 3);
199  std::vector<vpImagePoint>::iterator it1;
200  std::vector<double>::iterator it2;
201  vpImagePoint pt;
202  double w = 0;
203 
204  for (unsigned int j = 0; j <= l_p - l_s; j++) {
205  Rw[j][0] = (l_controlPoints[l_k - l_p + j]).get_i() * l_weights[l_k - l_p + j];
206  Rw[j][1] = (l_controlPoints[l_k - l_p + j]).get_j() * l_weights[l_k - l_p + j];
207  Rw[j][2] = l_weights[l_k - l_p + j];
208  }
209 
210  it1 = l_controlPoints.begin();
211  l_controlPoints.insert(it1 + (int)l_k - (int)l_s, l_r, pt);
212  it2 = l_weights.begin();
213  l_weights.insert(it2 + (int)l_k - (int)l_s, l_r, w);
214 
215  unsigned int L = 0;
216  double alpha;
217  for (unsigned int j = 1; j <= l_r; j++) {
218  L = l_k - l_p + j;
219 
220  for (unsigned int i = 0; i <= l_p - j - l_s; i++) {
221  alpha = (l_u - l_knots[L + i]) / (l_knots[i + l_k + 1] - l_knots[L + i]);
222  Rw[i][0] = alpha * Rw[i + 1][0] + (1.0 - alpha) * Rw[i][0];
223  Rw[i][1] = alpha * Rw[i + 1][1] + (1.0 - alpha) * Rw[i][1];
224  Rw[i][2] = alpha * Rw[i + 1][2] + (1.0 - alpha) * Rw[i][2];
225  }
226 
227  pt.set_ij(Rw[0][0] / Rw[0][2], Rw[0][1] / Rw[0][2]);
228  l_controlPoints[L] = pt;
229  l_weights[L] = Rw[0][2];
230 
231  pt.set_ij(Rw[l_p - j - l_s][0] / Rw[l_p - j - l_s][2], Rw[l_p - j - l_s][1] / Rw[l_p - j - l_s][2]);
232  l_controlPoints[l_k + l_r - j - l_s] = pt;
233  l_weights[l_k + l_r - j - l_s] = Rw[l_p - j - l_s][2];
234  }
235 
236  for (unsigned int j = L + 1; j < l_k - l_s; j++) {
237  pt.set_ij(Rw[j - L][0] / Rw[j - L][2], Rw[j - L][1] / Rw[j - L][2]);
238  l_controlPoints[j] = pt;
239  l_weights[j] = Rw[j - L][2];
240  }
241 
242  it2 = l_knots.begin();
243  l_knots.insert(it2 + (int)l_k, l_r, l_u);
244 }
245 
246 void vpNurbs::curveKnotIns(double u, unsigned int s, unsigned int r)
247 {
248  unsigned int i = findSpan(u);
249  curveKnotIns(u, i, s, r, p, knots, controlPoints, weights);
250 }
251 
252 
253 void vpNurbs::refineKnotVectCurve(double *l_x, unsigned int l_r, unsigned int l_p, std::vector<double> &l_knots,
254  std::vector<vpImagePoint> &l_controlPoints, std::vector<double> &l_weights)
255 {
256  unsigned int a = findSpan(l_x[0], l_p, l_knots);
257  unsigned int b = findSpan(l_x[l_r], l_p, l_knots);
258  b++;
259 
260  unsigned int n = (unsigned int)l_controlPoints.size();
261  unsigned int m = (unsigned int)l_knots.size();
262 
263  for (unsigned int j = 0; j < n; j++) {
264  l_controlPoints[j].set_ij(l_controlPoints[j].get_i() * l_weights[j], l_controlPoints[j].get_j() * l_weights[j]);
265  }
266 
267  std::vector<double> l_knots_tmp(l_knots);
268  std::vector<vpImagePoint> l_controlPoints_tmp(l_controlPoints);
269  std::vector<double> l_weights_tmp(l_weights);
270 
271  vpImagePoint pt;
272  double w = 0;
273 
274  for (unsigned int j = 0; j <= l_r; j++) {
275  l_controlPoints.push_back(pt);
276  l_weights.push_back(w);
277  l_knots.push_back(w);
278  }
279 
280  for (unsigned int j = b + l_p; j <= m - 1; j++)
281  l_knots[j + l_r + 1] = l_knots_tmp[j];
282 
283  for (unsigned int j = b - 1; j <= n - 1; j++) {
284  l_controlPoints[j + l_r + 1] = l_controlPoints_tmp[j];
285  l_weights[j + l_r + 1] = l_weights_tmp[j];
286  }
287 
288  unsigned int i = b + l_p - 1;
289  unsigned int k = b + l_p + l_r;
290 
291  {
292  unsigned int j = l_r + 1;
293  do {
294  j--;
295  while (l_x[j] <= l_knots[i] && i > a) {
296  l_controlPoints[k - l_p - 1] = l_controlPoints_tmp[i - l_p - 1];
297  l_weights[k - l_p - 1] = l_weights_tmp[i - l_p - 1];
298  l_knots[k] = l_knots_tmp[i];
299  k--;
300  i--;
301  }
302 
303  l_controlPoints[k - l_p - 1] = l_controlPoints[k - l_p];
304  l_weights[k - l_p - 1] = l_weights[k - l_p];
305 
306  for (unsigned int l = 1; l <= l_p; l++) {
307  unsigned int ind = k - l_p + l;
308  double alpha = l_knots[k + l] - l_x[j];
309  // if (vpMath::abs(alpha) == 0.0)
310  if (std::fabs(alpha) <= std::numeric_limits<double>::epsilon()) {
311  l_controlPoints[ind - 1] = l_controlPoints[ind];
312  l_weights[ind - 1] = l_weights[ind];
313  }
314  else {
315  alpha = alpha / (l_knots[k + l] - l_knots_tmp[i - l_p + l]);
316  l_controlPoints[ind - 1].set_i(alpha * l_controlPoints[ind - 1].get_i() +
317  (1.0 - alpha) * l_controlPoints[ind].get_i());
318  l_controlPoints[ind - 1].set_j(alpha * l_controlPoints[ind - 1].get_j() +
319  (1.0 - alpha) * l_controlPoints[ind].get_j());
320  l_weights[ind - 1] = alpha * l_weights[ind - 1] + (1.0 - alpha) * l_weights[ind];
321  }
322  }
323  l_knots[k] = l_x[j];
324  k--;
325  } while (j != 0);
326  }
327 
328  for (unsigned int j = 0; j < n; j++) {
329  l_controlPoints[j].set_ij(l_controlPoints[j].get_i() / l_weights[j], l_controlPoints[j].get_j() / l_weights[j]);
330  }
331 }
332 
333 void vpNurbs::refineKnotVectCurve(double *x, unsigned int r)
334 {
335  refineKnotVectCurve(x, r, p, knots, controlPoints, weights);
336 }
337 
338 unsigned int vpNurbs::removeCurveKnot(double l_u, unsigned int l_r, unsigned int l_num, double l_TOL, unsigned int l_s,
339  unsigned int l_p, std::vector<double> &l_knots,
340  std::vector<vpImagePoint> &l_controlPoints, std::vector<double> &l_weights)
341 {
342  unsigned int n = (unsigned int)l_controlPoints.size();
343  unsigned int m = n + l_p + 1;
344 
345  for (unsigned int j = 0; j < n; j++) {
346  l_controlPoints[j].set_ij(l_controlPoints[j].get_i() * l_weights[j], l_controlPoints[j].get_j() * l_weights[j]);
347  }
348 
349  unsigned int ord = l_p + 1;
350  double fout = (2 * l_r - l_s - l_p) / 2.;
351  unsigned int last = l_r - l_s;
352  unsigned int first = l_r - l_p;
353  unsigned int tblSize = 2 * l_p + 1;
354  vpImagePoint *tempP = new vpImagePoint[tblSize];
355  double *tempW = new double[tblSize];
356  vpImagePoint pt;
357  unsigned int t = 0;
358  double alfi = 0;
359  double alfj = 0;
360  unsigned int i, j;
361 
362  for (t = 0; t < l_num; t++) {
363  unsigned int off = first - 1;
364  tempP[0] = l_controlPoints[off];
365  tempW[0] = l_weights[off];
366  tempP[last + 1 - off] = l_controlPoints[last + 1];
367  tempW[last + 1 - off] = l_weights[last + 1];
368  i = first;
369  j = last;
370  unsigned int ii = 1;
371  unsigned int jj = last - off;
372  int remflag = 0;
373  while (j - i > t) {
374  alfi = (l_u - l_knots[i]) / (l_knots[i + ord + t] - l_knots[i]);
375  alfj = (l_u - l_knots[j - t]) / (l_knots[j + ord] - l_knots[j - t]);
376  pt.set_i((l_controlPoints[i].get_i() - (1.0 - alfi) * tempP[ii - 1].get_i()) / alfi);
377  tempP[ii].set_i((l_controlPoints[i].get_i() - (1.0 - alfi) * tempP[ii - 1].get_i()) / alfi);
378  tempP[ii].set_j((l_controlPoints[i].get_j() - (1.0 - alfi) * tempP[ii - 1].get_j()) / alfi);
379  tempW[ii] = ((l_weights[i] - (1.0 - alfi) * tempW[ii - 1]) / alfi);
380  tempP[jj].set_i((l_controlPoints[j].get_i() - alfj * tempP[jj + 1].get_i()) / (1.0 - alfj));
381  tempP[jj].set_j((l_controlPoints[j].get_j() - alfj * tempP[jj + 1].get_j()) / (1.0 - alfj));
382  tempW[jj] = ((l_weights[j] - alfj * tempW[jj + 1]) / (1.0 - alfj));
383  i++;
384  j--;
385  ii++;
386  jj--;
387  }
388 
389  if (j - i < t) {
390  double distancei = tempP[ii - 1].get_i() - tempP[jj + 1].get_i();
391  double distancej = tempP[ii - 1].get_j() - tempP[jj + 1].get_j();
392  double distancew = tempW[ii - 1] - tempW[jj + 1];
393  double distance = sqrt(vpMath::sqr(distancei) + vpMath::sqr(distancej) + vpMath::sqr(distancew));
394  if (distance <= l_TOL)
395  remflag = 1;
396  }
397  else {
398  alfi = (l_u - l_knots[i]) / (l_knots[i + ord + t] - l_knots[i]);
399  double distancei =
400  l_controlPoints[i].get_i() - (alfi * tempP[ii + t + 1].get_i() + (1.0 - alfi) * tempP[ii - 1].get_i());
401  double distancej =
402  l_controlPoints[i].get_j() - (alfi * tempP[ii + t + 1].get_j() + (1.0 - alfi) * tempP[ii - 1].get_j());
403  double distancew = l_weights[i] - (alfi * tempW[ii + t + 1] + (1.0 - alfi) * tempW[ii - 1]);
404  double distance = sqrt(vpMath::sqr(distancei) + vpMath::sqr(distancej) + vpMath::sqr(distancew));
405  if (distance <= l_TOL)
406  remflag = 1;
407  }
408  if (remflag == 0)
409  break;
410  else {
411  i = first;
412  j = last;
413  while (j - i > t) {
414  l_controlPoints[i].set_i(tempP[i - off].get_i());
415  l_controlPoints[i].set_j(tempP[i - off].get_j());
416  l_weights[i] = tempW[i - off];
417  l_controlPoints[j].set_i(tempP[j - off].get_i());
418  l_controlPoints[j].set_j(tempP[j - off].get_j());
419  l_weights[j] = tempW[j - off];
420  i++;
421  j--;
422  }
423  }
424  first--;
425  last++;
426  }
427  if (t == 0) {
428  delete[] tempP;
429  delete[] tempW;
430  return t;
431  }
432  for (unsigned int k = l_r + 1; k <= m; k++)
433  l_knots[k - t] = l_knots[k];
434  j = (unsigned int)fout;
435  i = j;
436  for (unsigned int k = 1; k < t; k++) {
437  if (k % 2)
438  i++;
439  else
440  j--;
441  }
442  for (unsigned int k = i + 1; k <= n; k++) {
443  l_controlPoints[j].set_i(l_controlPoints[k].get_i());
444  l_controlPoints[j].set_j(l_controlPoints[k].get_j());
445  l_weights[j] = l_weights[k];
446  j++;
447  }
448  for (unsigned int k = 0; k < t; k++) {
449  l_knots.erase(l_knots.end() - 1);
450  l_controlPoints.erase(l_controlPoints.end() - 1);
451  }
452 
453  for (unsigned int k = 0; k < l_controlPoints.size(); k++)
454  l_controlPoints[k].set_ij(l_controlPoints[k].get_i() / l_weights[k], l_controlPoints[k].get_j() / l_weights[k]);
455 
456  delete[] tempP;
457  delete[] tempW;
458  return t;
459 }
460 
461 unsigned int vpNurbs::removeCurveKnot(double l_u, unsigned int l_r, unsigned int l_num, double l_TOL)
462 {
463  return removeCurveKnot(l_u, l_r, l_num, l_TOL, 0, p, knots, controlPoints, weights);
464 }
465 
466 void vpNurbs::globalCurveInterp(std::vector<vpImagePoint> &l_crossingPoints, unsigned int l_p,
467  std::vector<double> &l_knots, std::vector<vpImagePoint> &l_controlPoints,
468  std::vector<double> &l_weights)
469 {
470  if (l_p == 0) {
471  // vpERROR_TRACE("Bad degree of the NURBS basis functions");
472  throw(vpException(vpException::badValue, "Bad degree of the NURBS basis functions"));
473  }
474 
475  l_knots.clear();
476  l_controlPoints.clear();
477  l_weights.clear();
478  unsigned int n = (unsigned int)l_crossingPoints.size() - 1;
479  unsigned int m = n + l_p + 1;
480 
481  double d = 0;
482  for (unsigned int k = 1; k <= n; k++)
483  d = d + distance(l_crossingPoints[k], 1, l_crossingPoints[k - 1], 1);
484 
485  // Compute ubar
486  std::vector<double> ubar;
487  ubar.push_back(0.0);
488  for (unsigned int k = 1; k < n; k++) {
489  ubar.push_back(ubar[k - 1] + distance(l_crossingPoints[k], 1, l_crossingPoints[k - 1], 1) / d);
490  }
491  ubar.push_back(1.0);
492 
493  // Compute the knot vector
494  for (unsigned int k = 0; k <= l_p; k++)
495  l_knots.push_back(0.0);
496 
497  double sum = 0;
498  for (unsigned int k = 1; k <= l_p; k++)
499  sum = sum + ubar[k];
500 
501  // Centripetal method
502  for (unsigned int k = 1; k <= n - l_p; k++) {
503  l_knots.push_back(sum / l_p);
504  sum = sum - ubar[k - 1] + ubar[l_p + k - 1];
505  }
506 
507  for (unsigned int k = m - l_p; k <= m; k++)
508  l_knots.push_back(1.0);
509 
510  vpMatrix A(n + 1, n + 1);
511  vpBasisFunction *N;
512 
513  for (unsigned int i = 0; i <= n; i++) {
514  unsigned int span = findSpan(ubar[i], l_p, l_knots);
515  N = computeBasisFuns(ubar[i], span, l_p, l_knots);
516  for (unsigned int k = 0; k <= l_p; k++)
517  A[i][span - l_p + k] = N[k].value;
518  delete[] N;
519  }
520  // vpMatrix Ainv = A.inverseByLU();
521  vpMatrix Ainv;
522  A.pseudoInverse(Ainv);
523  vpColVector Qi(n + 1);
524  vpColVector Qj(n + 1);
525  vpColVector Qw(n + 1);
526  for (unsigned int k = 0; k <= n; k++) {
527  Qi[k] = l_crossingPoints[k].get_i();
528  Qj[k] = l_crossingPoints[k].get_j();
529  }
530  Qw = 1;
531  vpColVector Pi = Ainv * Qi;
532  vpColVector Pj = Ainv * Qj;
533  vpColVector Pw = Ainv * Qw;
534 
535  vpImagePoint pt;
536  for (unsigned int k = 0; k <= n; k++) {
537  pt.set_ij(Pi[k], Pj[k]);
538  l_controlPoints.push_back(pt);
539  l_weights.push_back(Pw[k]);
540  }
541 }
542 
544 {
545  std::vector<vpImagePoint> v_crossingPoints;
546  l_crossingPoints.front();
547  vpMeSite s = l_crossingPoints.value();
548  vpImagePoint pt(s.get_ifloat(), s.get_jfloat());
549  vpImagePoint pt_1 = pt;
550  v_crossingPoints.push_back(pt);
551  l_crossingPoints.next();
552  while (!l_crossingPoints.outside()) {
553  s = l_crossingPoints.value();
554  pt.set_ij(s.get_ifloat(), s.get_jfloat());
555  if (vpImagePoint::distance(pt_1, pt) >= 10) {
556  v_crossingPoints.push_back(pt);
557  pt_1 = pt;
558  }
559  l_crossingPoints.next();
560  }
561  globalCurveInterp(v_crossingPoints, p, knots, controlPoints, weights);
562 }
563 
564 void vpNurbs::globalCurveInterp(const std::list<vpImagePoint> &l_crossingPoints)
565 {
566  std::vector<vpImagePoint> v_crossingPoints;
567  for (std::list<vpImagePoint>::const_iterator it = l_crossingPoints.begin(); it != l_crossingPoints.end(); ++it) {
568  v_crossingPoints.push_back(*it);
569  }
570  globalCurveInterp(v_crossingPoints, p, knots, controlPoints, weights);
571 }
572 
573 
574 void vpNurbs::globalCurveInterp(const std::list<vpMeSite> &l_crossingPoints)
575 {
576  std::vector<vpImagePoint> v_crossingPoints;
577  vpMeSite s = l_crossingPoints.front();
578  vpImagePoint pt(s.get_ifloat(), s.get_jfloat());
579  vpImagePoint pt_1 = pt;
580  v_crossingPoints.push_back(pt);
581  std::list<vpMeSite>::const_iterator it = l_crossingPoints.begin();
582  ++it;
583  for (; it != l_crossingPoints.end(); ++it) {
584  vpImagePoint pt_tmp(it->get_ifloat(), it->get_jfloat());
585  if (vpImagePoint::distance(pt_1, pt_tmp) >= 10) {
586  v_crossingPoints.push_back(pt_tmp);
587  pt_1 = pt_tmp;
588  }
589  }
590  globalCurveInterp(v_crossingPoints, p, knots, controlPoints, weights);
591 }
592 
593 void vpNurbs::globalCurveInterp() { globalCurveInterp(crossingPoints, p, knots, controlPoints, weights); }
594 
595 void vpNurbs::globalCurveApprox(std::vector<vpImagePoint> &l_crossingPoints, unsigned int l_p, unsigned int l_n,
596  std::vector<double> &l_knots, std::vector<vpImagePoint> &l_controlPoints,
597  std::vector<double> &l_weights)
598 {
599  l_knots.clear();
600  l_controlPoints.clear();
601  l_weights.clear();
602  unsigned int m = (unsigned int)l_crossingPoints.size() - 1;
603 
604  double d = 0;
605  for (unsigned int k = 1; k <= m; k++)
606  d = d + distance(l_crossingPoints[k], 1, l_crossingPoints[k - 1], 1);
607 
608  // Compute ubar
609  std::vector<double> ubar;
610  ubar.push_back(0.0);
611  for (unsigned int k = 1; k < m; k++)
612  ubar.push_back(ubar[k - 1] + distance(l_crossingPoints[k], 1, l_crossingPoints[k - 1], 1) / d);
613  ubar.push_back(1.0);
614 
615  // Compute the knot vector
616  for (unsigned int k = 0; k <= l_p; k++)
617  l_knots.push_back(0.0);
618 
619  d = (double)(m + 1) / (double)(l_n - l_p + 1);
620 
621  for (unsigned int j = 1; j <= l_n - l_p; j++) {
622  double i = floor(j * d);
623  double alpha = j * d - i;
624  l_knots.push_back((1.0 - alpha) * ubar[(unsigned int)i - 1] + alpha * ubar[(unsigned int)i]);
625  }
626 
627  for (unsigned int k = 0; k <= l_p; k++)
628  l_knots.push_back(1.0);
629 
630  // Compute Rk
631  std::vector<vpImagePoint> Rk;
632  vpBasisFunction *N;
633  for (unsigned int k = 1; k <= m - 1; k++) {
634  unsigned int span = findSpan(ubar[k], l_p, l_knots);
635  if (span == l_p && span == l_n) {
636  N = computeBasisFuns(ubar[k], span, l_p, l_knots);
637  vpImagePoint pt(l_crossingPoints[k].get_i() - N[0].value * l_crossingPoints[0].get_i() -
638  N[l_p].value * l_crossingPoints[m].get_i(),
639  l_crossingPoints[k].get_j() - N[0].value * l_crossingPoints[0].get_j() -
640  N[l_p].value * l_crossingPoints[m].get_j());
641  Rk.push_back(pt);
642  delete[] N;
643  }
644  else if (span == l_p) {
645  N = computeBasisFuns(ubar[k], span, l_p, l_knots);
646  vpImagePoint pt(l_crossingPoints[k].get_i() - N[0].value * l_crossingPoints[0].get_i(),
647  l_crossingPoints[k].get_j() - N[0].value * l_crossingPoints[0].get_j());
648  Rk.push_back(pt);
649  delete[] N;
650  }
651  else if (span == l_n) {
652  N = computeBasisFuns(ubar[k], span, l_p, l_knots);
653  vpImagePoint pt(l_crossingPoints[k].get_i() - N[l_p].value * l_crossingPoints[m].get_i(),
654  l_crossingPoints[k].get_j() - N[l_p].value * l_crossingPoints[m].get_j());
655  Rk.push_back(pt);
656  delete[] N;
657  }
658  else {
659  Rk.push_back(l_crossingPoints[k]);
660  }
661  }
662 
663  vpMatrix A(m - 1, l_n - 1);
664  // Compute A
665  for (unsigned int i = 1; i <= m - 1; i++) {
666  unsigned int span = findSpan(ubar[i], l_p, l_knots);
667  N = computeBasisFuns(ubar[i], span, l_p, l_knots);
668  for (unsigned int k = 0; k <= l_p; k++) {
669  if (N[k].i > 0 && N[k].i < l_n)
670  A[i - 1][N[k].i - 1] = N[k].value;
671  }
672  delete[] N;
673  }
674 
675  vpColVector Ri(l_n - 1);
676  vpColVector Rj(l_n - 1);
677  vpColVector Rw(l_n - 1);
678  for (unsigned int i = 0; i < l_n - 1; i++) {
679  double sum = 0;
680  for (unsigned int k = 0; k < m - 1; k++)
681  sum = sum + A[k][i] * Rk[k].get_i();
682  Ri[i] = sum;
683  sum = 0;
684  for (unsigned int k = 0; k < m - 1; k++)
685  sum = sum + A[k][i] * Rk[k].get_j();
686  Rj[i] = sum;
687  sum = 0;
688  for (unsigned int k = 0; k < m - 1; k++)
689  sum = sum + A[k][i]; // The crossing points weigths are equal to 1.
690  Rw[i] = sum;
691  }
692 
693  vpMatrix AtA = A.AtA();
694  vpMatrix AtAinv;
695  AtA.pseudoInverse(AtAinv);
696 
697  vpColVector Pi = AtAinv * Ri;
698  vpColVector Pj = AtAinv * Rj;
699  vpColVector Pw = AtAinv * Rw;
700 
701  vpImagePoint pt;
702  l_controlPoints.push_back(l_crossingPoints[0]);
703  l_weights.push_back(1.0);
704  for (unsigned int k = 0; k < l_n - 1; k++) {
705  pt.set_ij(Pi[k], Pj[k]);
706  l_controlPoints.push_back(pt);
707  l_weights.push_back(Pw[k]);
708  }
709  l_controlPoints.push_back(l_crossingPoints[m]);
710  l_weights.push_back(1.0);
711 }
712 
713 
714 void vpNurbs::globalCurveApprox(vpList<vpMeSite> &l_crossingPoints, unsigned int n)
715 {
716  std::vector<vpImagePoint> v_crossingPoints;
717  l_crossingPoints.front();
718  while (!l_crossingPoints.outside()) {
719  vpMeSite s = l_crossingPoints.value();
720  vpImagePoint pt(s.get_ifloat(), s.get_jfloat());
721  v_crossingPoints.push_back(pt);
722  l_crossingPoints.next();
723  }
724  globalCurveApprox(v_crossingPoints, p, n, knots, controlPoints, weights);
725 }
726 
727 
728 void vpNurbs::globalCurveApprox(const std::list<vpImagePoint> &l_crossingPoints, unsigned int n)
729 {
730  std::vector<vpImagePoint> v_crossingPoints;
731  for (std::list<vpImagePoint>::const_iterator it = l_crossingPoints.begin(); it != l_crossingPoints.end(); ++it) {
732  v_crossingPoints.push_back(*it);
733  }
734  globalCurveApprox(v_crossingPoints, p, n, knots, controlPoints, weights);
735 }
736 
737 void vpNurbs::globalCurveApprox(const std::list<vpMeSite> &l_crossingPoints, unsigned int n)
738 {
739  std::vector<vpImagePoint> v_crossingPoints;
740  for (std::list<vpMeSite>::const_iterator it = l_crossingPoints.begin(); it != l_crossingPoints.end(); ++it) {
741  vpImagePoint pt(it->get_ifloat(), it->get_jfloat());
742  v_crossingPoints.push_back(pt);
743  }
744  globalCurveApprox(v_crossingPoints, p, n, knots, controlPoints, weights);
745 }
746 
747 void vpNurbs::globalCurveApprox(unsigned int n)
748 {
749  globalCurveApprox(crossingPoints, p, n, knots, controlPoints, weights);
750 }
751 END_VISP_NAMESPACE
Class that provides tools to compute and manipulate a B-Spline curve.
Definition: vpBSpline.h:108
static unsigned int findSpan(double l_u, unsigned int l_p, const std::vector< double > &l_knots)
Definition: vpBSpline.cpp:80
static vpBasisFunction ** computeDersBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, const std::vector< double > &l_knots)
Definition: vpBSpline.cpp:229
static vpBasisFunction * computeBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, const std::vector< double > &l_knots)
Definition: vpBSpline.cpp:143
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:73
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
void set_j(double jj)
Definition: vpImagePoint.h:309
double get_j() const
Definition: vpImagePoint.h:125
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_ij(double ii, double jj)
Definition: vpImagePoint.h:320
void set_i(double ii)
Definition: vpImagePoint.h:298
double get_i() const
Definition: vpImagePoint.h:114
Provide simple list management.
Definition: vpList.h:110
void next(void)
position the current element on the next one
Definition: vpList.h:245
void front(void)
Position the current element on the first element of the list.
Definition: vpList.h:318
bool outside(void) const
Test if the current element is outside the list (on the virtual element)
Definition: vpList.h:351
type & value(void)
return the value of the current element
Definition: vpList.h:264
static double sqr(double x)
Definition: vpMath.h:203
static long double comb(unsigned int n, unsigned int p)
Definition: vpMath.h:394
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
vpMatrix AtA() const
vpMatrix pseudoInverse(double svThreshold=1e-6) const
void insert(const vpMatrix &A, unsigned int r, unsigned int c)
Definition: vpMatrix.cpp:1133
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
Definition: vpMeSite.h:68
double get_ifloat() const
Definition: vpMeSite.h:195
double get_jfloat() const
Definition: vpMeSite.h:201
Class that provides tools to compute and manipulate a Non Uniform Rational B-Spline curve.
Definition: vpNurbs.h:93
static void refineKnotVectCurve(double *l_x, unsigned int l_r, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:253
std::vector< double > weights
Vector which contains the weights associated to each control Points.
Definition: vpNurbs.h:96
static vpImagePoint computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:56
static void curveKnotIns(double l_u, unsigned int l_k, unsigned int l_s, unsigned int l_r, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:194
vpNurbs()
Definition: vpNurbs.cpp:52
static vpMatrix 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, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:105
static vpImagePoint * computeCurveDersPoint(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, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:156
static void globalCurveApprox(std::vector< vpImagePoint > &l_crossingPoints, unsigned int l_p, unsigned int l_n, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:595
static unsigned int removeCurveKnot(double l_u, unsigned int l_r, unsigned int l_num, double l_TOL, unsigned int l_s, unsigned int l_p, std::vector< double > &l_knots, std::vector< vpImagePoint > &l_controlPoints, std::vector< double > &l_weights)
Definition: vpNurbs.cpp:338
void globalCurveInterp()
Definition: vpNurbs.cpp:593