Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpNurbs.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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*/
44inline 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
53
54vpNurbs::vpNurbs(const vpNurbs &nurbs) : vpBSpline(nurbs), weights(nurbs.weights) { }
55
56vpImagePoint 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
105vpMatrix 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
133vpMatrix 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
156vpImagePoint *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
188{
189 unsigned int i = findSpan(u);
190 return computeCurveDersPoint(u, i, p, der, knots, controlPoints, weights);
191}
192
193
194void 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 + static_cast<int>(l_k) - static_cast<int>(l_s), l_r, pt);
212 it2 = l_weights.begin();
213 l_weights.insert(it2 + static_cast<int>(l_k) - static_cast<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 + static_cast<int>(l_k), l_r, l_u);
244}
245
246void 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
253void 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 = static_cast<unsigned int>(l_controlPoints.size());
261 unsigned int m = static_cast<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
333void vpNurbs::refineKnotVectCurve(double *x, unsigned int r)
334{
335 refineKnotVectCurve(x, r, p, knots, controlPoints, weights);
336}
337
338unsigned 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 = static_cast<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 = static_cast<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
461unsigned 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
466void 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 = static_cast<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
564void 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
574void 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
594
595void 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 = static_cast<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 = static_cast<double>(m + 1) / static_cast<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[static_cast<unsigned int>(i) - 1] + alpha * ubar[static_cast<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 weights 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
714void 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
728void 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
737void 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
747void vpNurbs::globalCurveApprox(unsigned int n)
748{
749 globalCurveApprox(crossingPoints, p, n, knots, controlPoints, weights);
750}
751END_VISP_NAMESPACE
static unsigned int findSpan(double l_u, unsigned int l_p, const std::vector< double > &l_knots)
Definition vpBSpline.cpp:63
unsigned int p
Degree of the B-Spline basis functions.
Definition vpBSpline.h:115
static vpBasisFunction ** computeDersBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, const std::vector< double > &l_knots)
std::vector< vpImagePoint > crossingPoints
Vector which contains the points used during the interpolation method.
Definition vpBSpline.h:117
std::vector< double > knots
Vector which contain the knots .
Definition vpBSpline.h:113
static vpBasisFunction * computeBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, const std::vector< double > &l_knots)
Implementation of column vector and the associated operations.
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 ...
void set_j(double jj)
double get_j() const
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_ij(double ii, double jj)
void set_i(double ii)
double get_i() const
Provide simple list management.
Definition vpList.h:109
void next(void)
position the current element on the next one
Definition vpList.h:244
void front(void)
Position the current element on the first element of the list.
Definition vpList.h:317
bool outside(void) const
Test if the current element is outside the list (on the virtual element).
Definition vpList.h:350
type & value(void)
return the value of the current element
Definition vpList.h:263
static double sqr(double x)
Definition vpMath.h:203
static long double comb(unsigned int n, unsigned int p)
Definition vpMath.h:398
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
vpMatrix AtA() const
vpMatrix pseudoInverse(double svThreshold=1e-6) const
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
Definition vpMeSite.h:75
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