Visual Servoing Platform  version 3.6.1 under development (2024-12-17)
vpCircle.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 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  * Visual feature circle.
32  *
33 *****************************************************************************/
34 
35 #include <visp3/core/vpCircle.h>
36 
37 #include <visp3/core/vpFeatureDisplay.h>
38 
39 BEGIN_VISP_NAMESPACE
41 {
42  const unsigned int val_7 = 7;
43  const unsigned int val_5 = 5;
44  oP.resize(val_7);
45  cP.resize(val_7);
46 
47  p.resize(val_5);
48 }
49 
59 void vpCircle::setWorldCoordinates(const vpColVector &oP_) { this->oP = oP_; }
60 
71 void vpCircle::setWorldCoordinates(double oA, double oB, double oC, double oX, double oY, double oZ, double R)
72 {
73  const unsigned int index_0 = 0;
74  const unsigned int index_1 = 1;
75  const unsigned int index_2 = 2;
76  const unsigned int index_3 = 3;
77  const unsigned int index_4 = 4;
78  const unsigned int index_5 = 5;
79  const unsigned int index_6 = 6;
80  oP[index_0] = oA;
81  oP[index_1] = oB;
82  oP[index_2] = oC;
83  oP[index_3] = oX;
84  oP[index_4] = oY;
85  oP[index_5] = oZ;
86  oP[index_6] = R;
87 }
88 
93 
106 {
107  init();
108  setWorldCoordinates(oP_);
109 }
110 
124 vpCircle::vpCircle(double oA, double oB, double oC, double oX, double oY, double oZ, double R)
125 {
126  init();
127  setWorldCoordinates(oA, oB, oC, oX, oY, oZ, R);
128 }
129 
134 
147 
166 void vpCircle::projection(const vpColVector &cP_, vpColVector &p_) const
167 {
168  const int val_2 = 2;
169  const int val_4 = 4;
170  const unsigned int val_6 = 6;
171  const unsigned int val_5 = 5;
172  double det_threshold = 1e-10;
173  p_.resize(val_5, false);
174  const unsigned int index_0 = 0;
175  const unsigned int index_1 = 1;
176  const unsigned int index_2 = 2;
177  const unsigned int index_3 = 3;
178  const unsigned int index_4 = 4;
179  const unsigned int index_5 = 5;
180 
181  vpColVector K(val_6);
182  {
183  double A = cP_[index_0];
184  double B = cP_[index_1];
185  double C = cP_[index_2];
186 
187  double X0 = cP_[index_3];
188  double Y0 = cP_[index_4];
189  double Z0 = cP_[index_5];
190 
191  double r = cP_[6];
192 
193  // projection
194  double s = ((X0 * X0) + (Y0 * Y0) + (Z0 * Z0)) - (r * r);
195  double det = (A * X0) + (B * Y0) + (C * Z0);
196  A = A / det;
197  B = B / det;
198  C = C / det;
199 
200  K[index_0] = (1 - (val_2 * A * X0)) + (A * A * s);
201  K[index_1] = (1 - (val_2 * B * Y0)) + (B * B * s);
202  K[index_2] = ((-A * Y0) - (B * X0)) + (A * B * s);
203  K[index_3] = ((-C * X0) - (A * Z0)) + (A * C * s);
204  K[index_4] = ((-C * Y0) - (B * Z0)) + (B * C * s);
205  K[index_5] = (1 - (val_2 * C * Z0)) + (C * C * s);
206  }
207 
208  double det = (K[index_2] * K[index_2]) - (K[index_0] * K[index_1]);
209  if (fabs(det) < det_threshold) {
210  throw(vpException(vpException::divideByZeroError, "Division by 0 in vpCircle::projection."));
211  }
212 
213  double xc = ((K[index_1] * K[index_3]) - (K[index_2] * K[index_4])) / det;
214  double yc = ((K[index_0] * K[index_4]) - (K[index_2] * K[index_3])) / det;
215 
216  double c = sqrt(((K[index_0] - K[index_1]) * (K[index_0] - K[index_1])) + (4 * K[index_2] * K[index_2]));
217  double s = 2 * (((K[index_0] * xc * xc) + (2 * K[index_2] * xc * yc) + (K[1] * yc * yc)) - K[index_5]);
218 
219  double A, B, E;
220 
221  if (fabs(K[index_2]) < std::numeric_limits<double>::epsilon()) {
222  E = 0.0;
223  if (K[0] > K[1]) {
224  A = sqrt(s / ((K[0] + K[1]) + c));
225  B = sqrt(s / ((K[0] + K[1]) - c));
226  }
227  else {
228  A = sqrt(s / ((K[0] + K[1]) - c));
229  B = sqrt(s / ((K[0] + K[1]) + c));
230  }
231  }
232  else {
233  E = ((K[1] - K[0]) + c) / (val_2 * K[index_2]);
234  if (fabs(E) > 1.0) {
235  A = sqrt(s / ((K[0] + K[1]) + c));
236  B = sqrt(s / ((K[0] + K[1]) - c));
237  }
238  else {
239  A = sqrt(s / ((K[0] + K[1]) - c));
240  B = sqrt(s / ((K[0] + K[1]) + c));
241  E = -1.0 / E;
242  }
243  }
244 
245  // Chaumette PhD Thesis 1990, eq 2.72 divided by 4 since n_ij = mu_ij_chaumette_thesis / 4
246  det = val_4 * (1.0 + vpMath::sqr(E));
247  double n20 = (vpMath::sqr(A) + vpMath::sqr(B * E)) / det;
248  double n11 = ((vpMath::sqr(A) - vpMath::sqr(B)) * E) / det;
249  double n02 = (vpMath::sqr(B) + vpMath::sqr(A * E)) / det;
250 
251  p_[index_0] = xc;
252  p_[index_1] = yc;
253  p_[index_2] = n20;
254  p_[index_3] = n11;
255  p_[index_4] = n02;
256 }
257 
269 {
270  const unsigned int val_7 = 7;
271  noP.resize(val_7, false);
272 
273  double A, B, C;
274  const unsigned int index_0 = 0;
275  const unsigned int index_1 = 1;
276  const unsigned int index_2 = 2;
277  const unsigned int index_3 = 3;
278  const unsigned int index_4 = 4;
279  const unsigned int index_5 = 5;
280  const unsigned int index_6 = 6;
281  A = (noMo[index_0][0] * oP[0]) + (noMo[index_0][1] * oP[1]) + (noMo[index_0][index_2] * oP[index_2]);
282  B = (noMo[index_1][0] * oP[0]) + (noMo[index_1][1] * oP[1]) + (noMo[index_1][index_2] * oP[index_2]);
283  C = (noMo[index_2][0] * oP[0]) + (noMo[index_2][1] * oP[1]) + (noMo[index_2][index_2] * oP[index_2]);
284 
285  double X0, Y0, Z0;
286  X0 = noMo[index_0][index_3] + (noMo[index_0][0] * oP[index_3]) + (noMo[index_0][1] * oP[index_4]) + (noMo[index_0][index_2] * oP[index_5]);
287  Y0 = noMo[index_1][index_3] + (noMo[index_1][0] * oP[index_3]) + (noMo[index_1][1] * oP[index_4]) + (noMo[index_1][index_2] * oP[index_5]);
288  Z0 = noMo[index_2][index_3] + (noMo[index_2][0] * oP[index_3]) + (noMo[index_2][1] * oP[index_4]) + (noMo[index_2][index_2] * oP[index_5]);
289  double R = oP[6];
290 
291  noP[index_0] = A;
292  noP[index_1] = B;
293  noP[index_2] = C;
294 
295  noP[index_3] = X0;
296  noP[index_4] = Y0;
297  noP[index_5] = Z0;
298 
299  noP[index_6] = R;
300 }
301 
309 {
310  double A, B, C;
311  const unsigned int index_0 = 0;
312  const unsigned int index_1 = 1;
313  const unsigned int index_2 = 2;
314  const unsigned int index_3 = 3;
315  const unsigned int index_4 = 4;
316  const unsigned int index_5 = 5;
317  const unsigned int index_6 = 6;
318  A = (cMo[index_0][0] * oP[0]) + (cMo[index_0][1] * oP[1]) + (cMo[index_0][index_2] * oP[index_2]);
319  B = (cMo[index_1][0] * oP[0]) + (cMo[index_1][1] * oP[1]) + (cMo[index_1][index_2] * oP[index_2]);
320  C = (cMo[index_2][0] * oP[0]) + (cMo[index_2][1] * oP[1]) + (cMo[index_2][index_2] * oP[index_2]);
321 
322  double X0, Y0, Z0;
323  X0 = cMo[index_0][index_3] + (cMo[index_0][0] * oP[index_3]) + (cMo[index_0][1] * oP[index_4]) + (cMo[index_0][index_2] * oP[index_5]);
324  Y0 = cMo[index_1][index_3] + (cMo[index_1][0] * oP[index_3]) + (cMo[index_1][1] * oP[index_4]) + (cMo[index_1][index_2] * oP[index_5]);
325  Z0 = cMo[index_2][index_3] + (cMo[index_2][0] * oP[index_3]) + (cMo[index_2][1] * oP[index_4]) + (cMo[index_2][index_2] * oP[index_5]);
326  double R = oP[6];
327 
328  cP[index_0] = A;
329  cP[index_1] = B;
330  cP[index_2] = C;
331 
332  cP[index_3] = X0;
333  cP[index_4] = Y0;
334  cP[index_5] = Z0;
335 
336  cP[index_6] = R;
337 }
338 
348 void vpCircle::display(const vpImage<unsigned char> &I, const vpCameraParameters &cam, const vpColor &color,
349  unsigned int thickness)
350 {
351  const unsigned int index_0 = 0;
352  const unsigned int index_1 = 1;
353  const unsigned int index_2 = 2;
354  const unsigned int index_3 = 3;
355  const unsigned int index_4 = 4;
356  vpFeatureDisplay::displayEllipse(p[index_0], p[index_1], p[index_2], p[index_3], p[index_4], cam, I, color, thickness);
357 }
358 
368 void vpCircle::display(const vpImage<vpRGBa> &I, const vpCameraParameters &cam, const vpColor &color,
369  unsigned int thickness)
370 {
371  const unsigned int index_0 = 0;
372  const unsigned int index_1 = 1;
373  const unsigned int index_2 = 2;
374  const unsigned int index_3 = 3;
375  const unsigned int index_4 = 4;
376  vpFeatureDisplay::displayEllipse(p[index_0], p[index_1], p[index_2], p[index_3], p[index_4], cam, I, color, thickness);
377 }
378 
391  const vpColor &color, unsigned int thickness)
392 {
393  vpColVector v_cP, v_p;
394  changeFrame(cMo, v_cP);
395  projection(v_cP, v_p);
396  const unsigned int index_0 = 0;
397  const unsigned int index_1 = 1;
398  const unsigned int index_2 = 2;
399  const unsigned int index_3 = 3;
400  const unsigned int index_4 = 4;
401  vpFeatureDisplay::displayEllipse(v_p[index_0], v_p[index_1], v_p[index_2], v_p[index_3], v_p[index_4], cam, I, color, thickness);
402 }
403 
416  const vpColor &color, unsigned int thickness)
417 {
418  vpColVector v_cP, v_p;
419  changeFrame(cMo, v_cP);
420  projection(v_cP, v_p);
421  const unsigned int index_0 = 0;
422  const unsigned int index_1 = 1;
423  const unsigned int index_2 = 2;
424  const unsigned int index_3 = 3;
425  const unsigned int index_4 = 4;
426  vpFeatureDisplay::displayEllipse(v_p[index_0], v_p[index_1], v_p[index_2], v_p[index_3], v_p[index_4], cam, I, color, thickness);
427 }
428 
431 {
432  vpCircle *feature = new vpCircle(*this);
433  return feature;
434 }
435 
453 void vpCircle::computeIntersectionPoint(const vpCircle &circle, const vpCameraParameters &cam, const double &rho,
454  const double &theta, double &i, double &j)
455 {
456  // This was taken from the code of art-v1. (from the artCylinder class)
457  double px = cam.get_px();
458  double py = cam.get_py();
459  double u0 = cam.get_u0();
460  double v0 = cam.get_v0();
461 
462  const unsigned int index_0 = 0;
463  const unsigned int index_1 = 1;
464  const unsigned int index_2 = 2;
465  const unsigned int index_3 = 3;
466  const unsigned int index_4 = 4;
467 
468  double n11 = circle.p[index_3];
469  double n02 = circle.p[index_4];
470  double n20 = circle.p[index_2];
471  double Xg = u0 + (circle.p[index_0] * px);
472  double Yg = v0 + (circle.p[index_1] * py);
473 
474  // Find Intersection between line and ellipse in the image.
475 
476  // Optimised calculation for X
477  double stheta = sin(theta);
478  double ctheta = cos(theta);
479  double sctheta = stheta * ctheta;
480  double m11yg = n11 * Yg;
481  double ctheta2 = vpMath::sqr(ctheta);
482  double m02xg = n02 * Xg;
483  double m11stheta = n11 * stheta;
484  j = ((((((((n11 * Xg * sctheta) - (n20 * Yg * sctheta)) + (n20 * rho * ctheta)) - m11yg) + (m11yg * ctheta2) + m02xg) -
485  (m02xg * ctheta2)) + (m11stheta * rho)) /
486  (((n20 * ctheta2) + (2.0 * m11stheta * ctheta) + n02) - (n02 * ctheta2)));
487  // Optimised calculation for Y
488  double rhom02 = rho * n02;
489  double sctheta2 = stheta * ctheta2;
490  double ctheta3 = ctheta2 * ctheta;
491  i = (-(((((((-rho * n11 * stheta * ctheta) - rhom02) + (rhom02 * ctheta2) + (n11 * Xg * sctheta2)) - (n20 * Yg * sctheta2)) -
492  (ctheta * n11 * Yg)) + (ctheta3 * n11 * Yg) + (ctheta * n02 * Xg)) - (ctheta3 * n02 * Xg)) /
493  (((n20 * ctheta2) + (2.0 * n11 * stheta * ctheta) + n02) - (n02 * ctheta2)) / stheta);
494 }
495 END_VISP_NAMESPACE
Generic class defining intrinsic camera parameters.
Class that defines a 3D circle in the object frame and allows forward projection of a 3D circle in th...
Definition: vpCircle.h:87
void display(const vpImage< unsigned char > &I, const vpCameraParameters &cam, const vpColor &color=vpColor::green, unsigned int thickness=1) VP_OVERRIDE
Definition: vpCircle.cpp:348
void changeFrame(const vpHomogeneousMatrix &noMo, vpColVector &noP) const VP_OVERRIDE
Definition: vpCircle.cpp:268
void projection() VP_OVERRIDE
Definition: vpCircle.cpp:146
void setWorldCoordinates(const vpColVector &oP) VP_OVERRIDE
Definition: vpCircle.cpp:59
void init() VP_OVERRIDE
Definition: vpCircle.cpp:40
vpCircle()
Definition: vpCircle.cpp:92
vpCircle * duplicate() const VP_OVERRIDE
For memory issue (used by the vpServo class only)
Definition: vpCircle.cpp:430
static void computeIntersectionPoint(const vpCircle &circle, const vpCameraParameters &cam, const double &rho, const double &theta, double &i, double &j)
Definition: vpCircle.cpp:453
virtual ~vpCircle() VP_OVERRIDE
Definition: vpCircle.cpp:133
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
void resize(unsigned int i, bool flagNullify=true)
Definition: vpColVector.h:1143
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:157
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ divideByZeroError
Division by zero.
Definition: vpException.h:70
static void displayEllipse(double x, double y, double n20, double n11, double n02, const vpCameraParameters &cam, const vpImage< unsigned char > &I, const vpColor &color=vpColor::green, unsigned int thickness=1)
Implementation of an homogeneous matrix and operations on such kind of matrices.
static double sqr(double x)
Definition: vpMath.h:203
vpColVector cP
Definition: vpTracker.h:73
vpColVector p
Definition: vpTracker.h:69