Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpBSpline.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 B-Spline
32 */
33
34#include <visp3/core/vpBSpline.h>
35#include <visp3/core/vpDebug.h>
36
44 : controlPoints(), knots(), p(3), // By default : p=3 for clubic spline
46{ }
47
63unsigned int vpBSpline::findSpan(double l_u, unsigned int l_p, const std::vector<double> &l_knots)
64{
65 unsigned int m = static_cast<unsigned int>(l_knots.size()) - 1;
66
67 if (l_u > l_knots.back()) {
68 // vpTRACE("l_u higher than the maximum value in the knot vector :
69 // %lf",l_u);
70 return (static_cast<unsigned int>(m - l_p - 1));
71 }
72
73 // if (l_u == l_knots.back())
74 if (std::fabs(l_u - l_knots.back()) <=
75 std::fabs(vpMath::maximum(l_u, l_knots.back())) * std::numeric_limits<double>::epsilon())
76 return (static_cast<unsigned int>(m - l_p - 1));
77
78 double low = l_p;
79 double high = m - l_p;
80 double middle = (low + high) / 2.0;
81
82 while (l_u < l_knots[static_cast<unsigned int>(middle)] || l_u >= l_knots[static_cast<unsigned int>(middle) + 1]) {
83 if (l_u < l_knots[static_cast<unsigned int>(vpMath::round(middle))])
84 high = middle;
85 else
86 low = middle;
87 middle = (low + high) / 2.0;
88 }
89
90 return static_cast<unsigned int>(middle);
91}
92
106unsigned int vpBSpline::findSpan(double u) const { return findSpan(u, p, knots); }
107
124vpBasisFunction *vpBSpline::computeBasisFuns(double l_u, unsigned int l_i, unsigned int l_p,
125 const std::vector<double> &l_knots)
126{
127 vpBasisFunction *N = new vpBasisFunction[l_p + 1];
128
129 N[0].value = 1.0;
130
131 double *left = new double[l_p + 1];
132 double *right = new double[l_p + 1];
133 double temp = 0.0;
134
135 for (unsigned int j = 1; j <= l_p; j++) {
136 left[j] = l_u - l_knots[l_i + 1 - j];
137 right[j] = l_knots[l_i + j] - l_u;
138 double saved = 0.0;
139
140 for (unsigned int r = 0; r < j; r++) {
141 temp = N[r].value / (right[r + 1] + left[j - r]);
142 N[r].value = saved + right[r + 1] * temp;
143 saved = left[j - r] * temp;
144 }
145 N[j].value = saved;
146 }
147 for (unsigned int j = 0; j < l_p + 1; j++) {
148 N[j].i = l_i - l_p + j;
149 N[j].p = l_p;
150 N[j].u = l_u;
151 N[j].k = 0;
152 }
153
154 delete[] left;
155 delete[] right;
156
157 return N;
158}
159
175vpBasisFunction *vpBSpline::computeBasisFuns(double u) const
176{
177 unsigned int i = findSpan(u);
178 return computeBasisFuns(u, i, p, knots);
179}
180
211vpBasisFunction **vpBSpline::computeDersBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der,
212 const std::vector<double> &l_knots)
213{
214 vpBasisFunction **N;
215 N = new vpBasisFunction *[l_der + 1];
216 for (unsigned int j = 0; j <= l_der; j++)
217 N[j] = new vpBasisFunction[l_p + 1];
218
219 vpMatrix a(2, l_p + 1);
220 vpMatrix ndu(l_p + 1, l_p + 1);
221 ndu[0][0] = 1.0;
222
223 double *left = new double[l_p + 1];
224 double *right = new double[l_p + 1];
225 double temp = 0.0;
226
227 for (unsigned int j = 1; j <= l_p; j++) {
228 left[j] = l_u - l_knots[l_i + 1 - j];
229 right[j] = l_knots[l_i + j] - l_u;
230 double saved = 0.0;
231
232 for (unsigned int r = 0; r < j; r++) {
233 ndu[j][r] = right[r + 1] + left[j - r];
234 temp = ndu[r][j - 1] / ndu[j][r];
235 ndu[r][j] = saved + right[r + 1] * temp;
236 saved = left[j - r] * temp;
237 }
238 ndu[j][j] = saved;
239 }
240
241 for (unsigned int j = 0; j <= l_p; j++) {
242 N[0][j].value = ndu[j][l_p];
243 N[0][j].i = l_i - l_p + j;
244 N[0][j].p = l_p;
245 N[0][j].u = l_u;
246 N[0][j].k = 0;
247 }
248
249 if (l_der > l_p) {
250 vpTRACE("l_der must be under or equal to l_p");
251 l_der = l_p;
252 }
253
254 double d;
255 int rk;
256 unsigned int pk;
257 unsigned int j1, j2;
258
259 for (unsigned int r = 0; r <= l_p; r++) {
260 unsigned int s1 = 0;
261 unsigned int s2 = 1;
262 a[0][0] = 1.0;
263 for (unsigned int k = 1; k <= l_der; k++) {
264 d = 0.0;
265 rk = static_cast<int>(r - k);
266 pk = l_p - k;
267 if (r >= k) {
268 a[s2][0] = a[s1][0] / ndu[pk + 1][rk];
269 d = a[s2][0] * ndu[static_cast<unsigned int>(rk)][pk];
270 }
271
272 if (rk >= -1)
273 j1 = 1;
274 else
275 j1 = static_cast<unsigned int>(-rk);
276
277 if (r - 1 <= pk)
278 j2 = k - 1;
279 else
280 j2 = l_p - r;
281
282 for (unsigned int j = j1; j <= j2; j++) {
283 a[s2][j] = (a[s1][j] - a[s1][j - 1]) / ndu[pk + 1][static_cast<unsigned int>(rk) + j];
284 d += a[s2][j] * ndu[static_cast<unsigned int>(rk) + j][pk];
285 }
286
287 if (r <= pk) {
288 a[s2][k] = -a[s1][k - 1] / ndu[pk + 1][r];
289 d += a[s2][k] * ndu[r][pk];
290 }
291 N[k][r].value = d;
292 N[k][r].i = l_i - l_p + r;
293 N[k][r].p = l_p;
294 N[k][r].u = l_u;
295 N[k][r].k = k;
296
297 s1 = (s1 + 1) % 2;
298 s2 = (s2 + 1) % 2;
299 }
300 }
301
302 double r = l_p;
303 for (unsigned int k = 1; k <= l_der; k++) {
304 for (unsigned int j = 0; j <= l_p; j++)
305 N[k][j].value *= r;
306 r *= (l_p - k);
307 }
308
309 delete[] left;
310 delete[] right;
311
312 return N;
313}
314
341vpBasisFunction **vpBSpline::computeDersBasisFuns(double u, unsigned int der) const
342{
343 unsigned int i = findSpan(u);
344 return computeDersBasisFuns(u, i, p, der, knots);
345}
346
359vpImagePoint vpBSpline::computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, const std::vector<double> &l_knots,
360 const std::vector<vpImagePoint> &l_controlPoints)
361{
362 vpBasisFunction *N = computeBasisFuns(l_u, l_i, l_p, l_knots);
363 vpImagePoint pt;
364
365 double ic = 0;
366 double jc = 0;
367 for (unsigned int j = 0; j <= l_p; j++) {
368 ic = ic + N[j].value * (l_controlPoints[l_i - l_p + j]).get_i();
369 jc = jc + N[j].value * (l_controlPoints[l_i - l_p + j]).get_j();
370 }
371
372 pt.set_i(ic);
373 pt.set_j(jc);
374
375 delete[] N;
376
377 return pt;
378}
379
389{
390 vpBasisFunction *N = computeBasisFuns(u);
391 vpImagePoint pt;
392
393 double ic = 0;
394 double jc = 0;
395 for (unsigned int j = 0; j <= p; j++) {
396 ic = ic + N[j].value * (controlPoints[N[0].i + j]).get_i();
397 jc = jc + N[j].value * (controlPoints[N[0].i + j]).get_j();
398 }
399
400 pt.set_i(ic);
401 pt.set_j(jc);
402
403 delete[] N;
404
405 return pt;
406}
407
428vpImagePoint *vpBSpline::computeCurveDers(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der,
429 const std::vector<double> &l_knots, const std::vector<vpImagePoint> &l_controlPoints)
430{
431 vpImagePoint *derivate = new vpImagePoint[l_der + 1];
432 vpBasisFunction **N;
433 N = computeDersBasisFuns(l_u, l_i, l_p, l_der, l_knots);
434
435 unsigned int du;
436 if (l_p < l_der) {
437 vpTRACE("l_der must be under or equal to l_p");
438 du = l_p;
439 }
440 else
441 du = l_der;
442
443 for (unsigned int k = 0; k <= du; k++) {
444 derivate[k].set_ij(0.0, 0.0);
445 for (unsigned int j = 0; j <= l_p; j++) {
446 derivate[k].set_i(derivate[k].get_i() + N[k][j].value * (l_controlPoints[l_i - l_p + j]).get_i());
447 derivate[k].set_j(derivate[k].get_j() + N[k][j].value * (l_controlPoints[l_i - l_p + j]).get_j());
448 }
449 }
450
451 for (unsigned int j = 0; j <= l_der; j++)
452 delete[] N[j];
453 delete[] N;
454
455 return derivate;
456}
457
474vpImagePoint *vpBSpline::computeCurveDers(double u, unsigned int der) const
475{
476 vpImagePoint *derivate = new vpImagePoint[der + 1];
477 vpBasisFunction **N;
478 N = computeDersBasisFuns(u, der);
479
480 unsigned int du;
481 if (p < der) {
482 vpTRACE("der must be under or equal to p");
483 du = p;
484 }
485 else
486 du = der;
487
488 for (unsigned int k = 0; k <= du; k++) {
489 derivate[k].set_ij(0.0, 0.0);
490 for (unsigned int j = 0; j <= p; j++) {
491 derivate[k].set_i(derivate[k].get_i() + N[k][j].value * (controlPoints[N[0][0].i - p + j]).get_i());
492 derivate[k].set_j(derivate[k].get_j() + N[k][j].value * (controlPoints[N[0][0].i - p + j]).get_j());
493 }
494 }
495
496 for (unsigned int j = 0; j <= der; j++)
497 delete[] N[j];
498 delete[] N;
499
500 return derivate;
501}
502END_VISP_NAMESPACE
static vpImagePoint computeCurvePoint(double l_u, unsigned int l_i, unsigned int l_p, const std::vector< double > &l_knots, const std::vector< vpImagePoint > &l_controlPoints)
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 vpImagePoint * computeCurveDers(double l_u, unsigned int l_i, unsigned int l_p, unsigned int l_der, const std::vector< double > &l_knots, const std::vector< vpImagePoint > &l_controlPoints)
static vpBasisFunction * computeBasisFuns(double l_u, unsigned int l_i, unsigned int l_p, const std::vector< double > &l_knots)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
void set_j(double jj)
void set_ij(double ii, double jj)
void set_i(double ii)
static Type maximum(const Type &a, const Type &b)
Definition vpMath.h:257
static int round(double x)
Definition vpMath.h:413
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
#define vpTRACE
Definition vpDebug.h:450