Visual Servoing Platform  version 3.6.1 under development (2024-11-14)
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  oP.resize(7);
43  cP.resize(7);
44 
45  p.resize(5);
46 }
47 
57 void vpCircle::setWorldCoordinates(const vpColVector &oP_) { this->oP = oP_; }
58 
69 void vpCircle::setWorldCoordinates(double oA, double oB, double oC, double oX, double oY, double oZ, double R)
70 {
71  const unsigned int index_0 = 0;
72  const unsigned int index_1 = 1;
73  const unsigned int index_2 = 2;
74  const unsigned int index_3 = 3;
75  const unsigned int index_4 = 4;
76  const unsigned int index_5 = 5;
77  const unsigned int index_6 = 6;
78  oP[index_0] = oA;
79  oP[index_1] = oB;
80  oP[index_2] = oC;
81  oP[index_3] = oX;
82  oP[index_4] = oY;
83  oP[index_5] = oZ;
84  oP[index_6] = R;
85 }
86 
91 
104 {
105  init();
106  setWorldCoordinates(oP_);
107 }
108 
122 vpCircle::vpCircle(double oA, double oB, double oC, double oX, double oY, double oZ, double R)
123 {
124  init();
125  setWorldCoordinates(oA, oB, oC, oX, oY, oZ, R);
126 }
127 
132 
145 
164 void vpCircle::projection(const vpColVector &cP_, vpColVector &p_) const
165 {
166  double det_threshold = 1e-10;
167  p_.resize(5, false);
168  const unsigned int index_0 = 0;
169  const unsigned int index_1 = 1;
170  const unsigned int index_2 = 2;
171  const unsigned int index_3 = 3;
172  const unsigned int index_4 = 4;
173  const unsigned int index_5 = 5;
174 
175  vpColVector K(6);
176  {
177  double A = cP_[index_0];
178  double B = cP_[index_1];
179  double C = cP_[index_2];
180 
181  double X0 = cP_[index_3];
182  double Y0 = cP_[index_4];
183  double Z0 = cP_[index_5];
184 
185  double r = cP_[6];
186 
187  // projection
188  double s = ((X0 * X0) + (Y0 * Y0) + (Z0 * Z0)) - (r * r);
189  double det = (A * X0) + (B * Y0) + (C * Z0);
190  A = A / det;
191  B = B / det;
192  C = C / det;
193 
194  K[index_0] = (1 - (2 * A * X0)) + (A * A * s);
195  K[index_1] = (1 - (2 * B * Y0)) + (B * B * s);
196  K[index_2] = ((-A * Y0) - (B * X0)) + (A * B * s);
197  K[index_3] = ((-C * X0) - (A * Z0)) + (A * C * s);
198  K[index_4] = ((-C * Y0) - (B * Z0)) + (B * C * s);
199  K[index_5] = (1 - (2 * C * Z0)) + (C * C * s);
200  }
201 
202  double det = (K[index_2] * K[index_2]) - (K[index_0] * K[index_1]);
203  if (fabs(det) < det_threshold) {
204  throw(vpException(vpException::divideByZeroError, "Division by 0 in vpCircle::projection."));
205  }
206 
207  double xc = ((K[index_1] * K[index_3]) - (K[index_2] * K[index_4])) / det;
208  double yc = ((K[index_0] * K[index_4]) - (K[index_2] * K[index_3])) / det;
209 
210  double c = sqrt(((K[index_0] - K[index_1]) * (K[index_0] - K[index_1])) + (4 * K[index_2] * K[index_2]));
211  double s = 2 * (((K[index_0] * xc * xc) + (2 * K[index_2] * xc * yc) + (K[1] * yc * yc)) - K[index_5]);
212 
213  double A, B, E;
214 
215  if (fabs(K[index_2]) < std::numeric_limits<double>::epsilon()) {
216  E = 0.0;
217  if (K[0] > K[1]) {
218  A = sqrt(s / ((K[0] + K[1]) + c));
219  B = sqrt(s / ((K[0] + K[1]) - c));
220  }
221  else {
222  A = sqrt(s / ((K[0] + K[1]) - c));
223  B = sqrt(s / ((K[0] + K[1]) + c));
224  }
225  }
226  else {
227  E = ((K[1] - K[0]) + c) / (2 * K[index_2]);
228  if (fabs(E) > 1.0) {
229  A = sqrt(s / ((K[0] + K[1]) + c));
230  B = sqrt(s / ((K[0] + K[1]) - c));
231  }
232  else {
233  A = sqrt(s / ((K[0] + K[1]) - c));
234  B = sqrt(s / ((K[0] + K[1]) + c));
235  E = -1.0 / E;
236  }
237  }
238 
239  // Chaumette PhD Thesis 1990, eq 2.72 divided by 4 since n_ij = mu_ij_chaumette_thesis / 4
240  det = 4 * (1.0 + vpMath::sqr(E));
241  double n20 = (vpMath::sqr(A) + vpMath::sqr(B * E)) / det;
242  double n11 = ((vpMath::sqr(A) - vpMath::sqr(B)) * E) / det;
243  double n02 = (vpMath::sqr(B) + vpMath::sqr(A * E)) / det;
244 
245  p_[index_0] = xc;
246  p_[index_1] = yc;
247  p_[index_2] = n20;
248  p_[index_3] = n11;
249  p_[index_4] = n02;
250 }
251 
263 {
264  noP.resize(7, false);
265 
266  double A, B, C;
267  const unsigned int index_0 = 0;
268  const unsigned int index_1 = 1;
269  const unsigned int index_2 = 2;
270  const unsigned int index_3 = 3;
271  const unsigned int index_4 = 4;
272  const unsigned int index_5 = 5;
273  const unsigned int index_6 = 6;
274  A = (noMo[index_0][0] * oP[0]) + (noMo[index_0][1] * oP[1]) + (noMo[index_0][index_2] * oP[index_2]);
275  B = (noMo[index_1][0] * oP[0]) + (noMo[index_1][1] * oP[1]) + (noMo[index_1][index_2] * oP[index_2]);
276  C = (noMo[index_2][0] * oP[0]) + (noMo[index_2][1] * oP[1]) + (noMo[index_2][index_2] * oP[index_2]);
277 
278  double X0, Y0, Z0;
279  X0 = noMo[index_0][index_3] + (noMo[index_0][0] * oP[3]) + (noMo[index_0][1] * oP[index_4]) + (noMo[index_0][index_2] * oP[index_5]);
280  Y0 = noMo[index_1][index_3] + (noMo[index_1][0] * oP[3]) + (noMo[index_1][1] * oP[index_4]) + (noMo[index_1][index_2] * oP[index_5]);
281  Z0 = noMo[index_2][index_3] + (noMo[index_2][0] * oP[3]) + (noMo[index_2][1] * oP[index_4]) + (noMo[index_2][index_2] * oP[index_5]);
282  double R = oP[6];
283 
284  noP[index_0] = A;
285  noP[index_1] = B;
286  noP[index_2] = C;
287 
288  noP[index_3] = X0;
289  noP[index_4] = Y0;
290  noP[index_5] = Z0;
291 
292  noP[index_6] = R;
293 }
294 
302 {
303  double A, B, C;
304  const unsigned int index_0 = 0;
305  const unsigned int index_1 = 1;
306  const unsigned int index_2 = 2;
307  const unsigned int index_3 = 3;
308  const unsigned int index_4 = 4;
309  const unsigned int index_5 = 5;
310  const unsigned int index_6 = 6;
311  A = (cMo[index_0][0] * oP[0]) + (cMo[index_0][1] * oP[1]) + (cMo[index_0][index_2] * oP[index_2]);
312  B = (cMo[index_1][0] * oP[0]) + (cMo[index_1][1] * oP[1]) + (cMo[index_1][index_2] * oP[index_2]);
313  C = (cMo[index_2][0] * oP[0]) + (cMo[index_2][1] * oP[1]) + (cMo[index_2][index_2] * oP[index_2]);
314 
315  double X0, Y0, Z0;
316  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]);
317  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]);
318  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]);
319  double R = oP[6];
320 
321  cP[index_0] = A;
322  cP[index_1] = B;
323  cP[index_2] = C;
324 
325  cP[index_3] = X0;
326  cP[index_4] = Y0;
327  cP[index_5] = Z0;
328 
329  cP[index_6] = R;
330 }
331 
341 void vpCircle::display(const vpImage<unsigned char> &I, const vpCameraParameters &cam, const vpColor &color,
342  unsigned int thickness)
343 {
344  const unsigned int index_0 = 0;
345  const unsigned int index_1 = 1;
346  const unsigned int index_2 = 2;
347  const unsigned int index_3 = 3;
348  const unsigned int index_4 = 4;
349  vpFeatureDisplay::displayEllipse(p[index_0], p[index_1], p[index_2], p[index_3], p[index_4], cam, I, color, thickness);
350 }
351 
361 void vpCircle::display(const vpImage<vpRGBa> &I, const vpCameraParameters &cam, const vpColor &color,
362  unsigned int thickness)
363 {
364  const unsigned int index_0 = 0;
365  const unsigned int index_1 = 1;
366  const unsigned int index_2 = 2;
367  const unsigned int index_3 = 3;
368  const unsigned int index_4 = 4;
369  vpFeatureDisplay::displayEllipse(p[index_0], p[index_1], p[index_2], p[index_3], p[index_4], cam, I, color, thickness);
370 }
371 
384  const vpColor &color, unsigned int thickness)
385 {
386  vpColVector v_cP, v_p;
387  changeFrame(cMo, v_cP);
388  projection(v_cP, v_p);
389  const unsigned int index_0 = 0;
390  const unsigned int index_1 = 1;
391  const unsigned int index_2 = 2;
392  const unsigned int index_3 = 3;
393  const unsigned int index_4 = 4;
394  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);
395 }
396 
409  const vpColor &color, unsigned int thickness)
410 {
411  vpColVector v_cP, v_p;
412  changeFrame(cMo, v_cP);
413  projection(v_cP, v_p);
414  const unsigned int index_0 = 0;
415  const unsigned int index_1 = 1;
416  const unsigned int index_2 = 2;
417  const unsigned int index_3 = 3;
418  const unsigned int index_4 = 4;
419  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);
420 }
421 
424 {
425  vpCircle *feature = new vpCircle(*this);
426  return feature;
427 }
428 
446 void vpCircle::computeIntersectionPoint(const vpCircle &circle, const vpCameraParameters &cam, const double &rho,
447  const double &theta, double &i, double &j)
448 {
449  // This was taken from the code of art-v1. (from the artCylinder class)
450  double px = cam.get_px();
451  double py = cam.get_py();
452  double u0 = cam.get_u0();
453  double v0 = cam.get_v0();
454 
455  const unsigned int index_0 = 0;
456  const unsigned int index_1 = 1;
457  const unsigned int index_2 = 2;
458  const unsigned int index_3 = 3;
459  const unsigned int index_4 = 4;
460 
461  double n11 = circle.p[index_3];
462  double n02 = circle.p[index_4];
463  double n20 = circle.p[index_2];
464  double Xg = u0 + (circle.p[index_0] * px);
465  double Yg = v0 + (circle.p[index_1] * py);
466 
467  // Find Intersection between line and ellipse in the image.
468 
469  // Optimised calculation for X
470  double stheta = sin(theta);
471  double ctheta = cos(theta);
472  double sctheta = stheta * ctheta;
473  double m11yg = n11 * Yg;
474  double ctheta2 = vpMath::sqr(ctheta);
475  double m02xg = n02 * Xg;
476  double m11stheta = n11 * stheta;
477  j = ((((((((n11 * Xg * sctheta) - (n20 * Yg * sctheta)) + (n20 * rho * ctheta)) - m11yg) + (m11yg * ctheta2) + m02xg) -
478  (m02xg * ctheta2)) + (m11stheta * rho)) /
479  (((n20 * ctheta2) + (2.0 * m11stheta * ctheta) + n02) - (n02 * ctheta2)));
480  // Optimised calculation for Y
481  double rhom02 = rho * n02;
482  double sctheta2 = stheta * ctheta2;
483  double ctheta3 = ctheta2 * ctheta;
484  i = (-(((((((-rho * n11 * stheta * ctheta) - rhom02) + (rhom02 * ctheta2) + (n11 * Xg * sctheta2)) - (n20 * Yg * sctheta2)) -
485  (ctheta * n11 * Yg)) + (ctheta3 * n11 * Yg) + (ctheta * n02 * Xg)) - (ctheta3 * n02 * Xg)) /
486  (((n20 * ctheta2) + (2.0 * n11 * stheta * ctheta) + n02) - (n02 * ctheta2)) / stheta);
487 }
488 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:341
void changeFrame(const vpHomogeneousMatrix &noMo, vpColVector &noP) const VP_OVERRIDE
Definition: vpCircle.cpp:262
void projection() VP_OVERRIDE
Definition: vpCircle.cpp:144
void setWorldCoordinates(const vpColVector &oP) VP_OVERRIDE
Definition: vpCircle.cpp:57
void init() VP_OVERRIDE
Definition: vpCircle.cpp:40
vpCircle()
Definition: vpCircle.cpp:90
vpCircle * duplicate() const VP_OVERRIDE
For memory issue (used by the vpServo class only)
Definition: vpCircle.cpp:423
static void computeIntersectionPoint(const vpCircle &circle, const vpCameraParameters &cam, const double &rho, const double &theta, double &i, double &j)
Definition: vpCircle.cpp:446
virtual ~vpCircle() VP_OVERRIDE
Definition: vpCircle.cpp:131
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