Visual Servoing Platform  version 3.6.1 under development (2025-02-17)
vpImageCircle.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  * Image circle, i.e. circle in the image space.
32  */
33 
34 #include <visp3/core/vpImageCircle.h>
35 #include <visp3/core/vpMath.h>
36 
37 BEGIN_VISP_NAMESPACE
39  : m_center()
40  , m_radius(0.)
41 {
42 
43 }
44 
45 vpImageCircle::vpImageCircle(const vpImagePoint &center, const float &radius)
46  : m_center(center)
47  , m_radius(radius)
48 {
49 
50 }
51 
52 #ifdef HAVE_OPENCV_CORE
53 vpImageCircle::vpImageCircle(const cv::Vec3f &vec)
54 {
55  const unsigned int index_0 = 0;
56  const unsigned int index_1 = 1;
57  const unsigned int index_2 = 2;
58  m_center = vpImagePoint(vec[index_1], vec[index_0]);
59  m_radius = vec[index_2];
60 }
61 #endif
62 
72 void computeIntersectionsLeftBorder(const float &u_c, const float &umin_roi, const float &radius,
73  float &delta_theta)
74 {
75  // --comment: umin_roi = u_c + r cos(theta)
76  // --comment: theta = acos of of umin_roi - u_c endof / r endof
77  const int val_2 = 2;
78  float theta1 = std::acos((umin_roi - u_c) / radius);
79  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
80  float theta2 = -1.f * theta1;
81  float theta_min = std::min<float>(theta1, theta2);
82  float theta_max = std::max<float>(theta1, theta2);
83  delta_theta = theta_max - theta_min;
84  if ((u_c < umin_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
85  delta_theta = 0.f;
86  }
87 }
88 
98 void computeIntersectionsRightBorder(const float &u_c, const float &umax_roi, const float &radius,
99  float &delta_theta)
100 {
101  // --comment: u = u_c + r cos(theta)
102  // --comment: theta = acos of of u - u_c endof / r endof
103  const int val_2 = 2;
104  float theta1 = std::acos((umax_roi - u_c) / radius);
105  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
106  float theta2 = -1.f * theta1;
107  float theta_min = std::min<float>(theta1, theta2);
108  float theta_max = std::max<float>(theta1, theta2);
109  delta_theta = (2.f * M_PI_FLOAT) - (theta_max - theta_min);
110  if ((u_c > umax_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
111  delta_theta = 0.f;
112  }
113 }
114 
124 void computeIntersectionsTopBorder(const float &v_c, const float &vmin_roi, const float &radius,
125  float &delta_theta)
126 {
127  // v = vc - r sin(theta) because the v-axis goes down
128  // theta = asin((vc - v)/r)
129  const int val_2 = 2;
130  float theta1 = std::asin((v_c - vmin_roi) / radius);
131  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
132 
133  float theta2 = 0.f;
134  if (theta1 >= 0.f) {
135  theta2 = M_PI_FLOAT - theta1;
136  }
137  else {
138  theta2 = -theta1 - M_PI_FLOAT;
139  }
140  float theta_min = std::min<float>(theta1, theta2);
141  float theta_max = std::max<float>(theta1, theta2);
142  if ((std::abs(theta_max - theta_min) * radius) < 1.f) {
143  // Between the maximum and minimum theta there is less than 1 pixel of difference
144  // It meens that the full circle is visible
145  delta_theta = 2.f * M_PI_FLOAT;
146  }
147  else if (theta1 > 0.f) {
148  delta_theta = (2.f * M_PI_FLOAT) - (theta_max - theta_min);
149  }
150  else {
151  delta_theta = theta_max - theta_min;
152  }
153  if ((v_c < vmin_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
154  delta_theta = 0.f;
155  }
156 }
157 
167 void computeIntersBottomBorder(const float &v_c, const float &vmax_roi, const float &radius,
168  float &delta_theta)
169 {
170  // v = vc - r sin(theta) because the v-axis goes down
171  // theta = asin((vc - v)/r)
172  const int val_2 = 2;
173  float theta1 = std::asin((v_c - vmax_roi) / radius);
174  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
175 
176  float theta2 = 0.f;
177  if (theta1 >= 0.f) {
178  theta2 = M_PI_FLOAT - theta1;
179  }
180  else {
181  theta2 = -theta1 - M_PI_FLOAT;
182  }
183  float theta_min = std::min<float>(theta1, theta2);
184  float theta_max = std::max<float>(theta1, theta2);
185  if ((std::abs(theta_max - theta_min) * radius) < 1.f) {
186  // Between the maximum and minimum theta there is less than 1 pixel of difference
187  // It meens that the full circle is visible
188  delta_theta = 2.f * M_PI_FLOAT;
189  }
190  else if (theta1 > 0.f) {
191  delta_theta = theta_max - theta_min;
192  }
193  else {
194  delta_theta = (2.f * M_PI_FLOAT) - (theta_max - theta_min);
195  }
196  if ((v_c > vmax_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
197  delta_theta = 0.f;
198  }
199 }
200 
215 void computePerpendicularAxesInters(const float &u_c, const float &v_c, const float &radius,
216  const float &crossing_u, const float &crossing_v,
217  std::pair<float, float> &theta_u_cross_min, std::pair<float, float> &theta_u_cross_max,
218  std::pair<float, float> &theta_v_cross_min, std::pair<float, float> &theta_v_cross_max)
219 {
220  // Computing the two angles for which the u-axis is crossed
221  // v = vc - r sin(theta) because the v-axis goes down
222  // theta = asin((vc - v)/r)
223  float theta_u_cross = std::asin((v_c - crossing_u) / radius);
224  theta_u_cross = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross);
225  float theta_u_cross_2 = 0.f;
226  if (theta_u_cross > 0) {
227  theta_u_cross_2 = M_PI_FLOAT - theta_u_cross;
228  }
229  else {
230  theta_u_cross_2 = -M_PI_FLOAT - theta_u_cross;
231  }
232  // Computing the corresponding u-coordinates at which the u-axis is crossed
233  float u_ucross = u_c + (radius * std::cos(theta_u_cross));
234  float u_ucross2 = u_c + (radius * std::cos(theta_u_cross_2));
235  // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second
236  if (u_ucross < u_ucross2) {
237  theta_u_cross_min.first = theta_u_cross;
238  theta_u_cross_min.second = u_ucross;
239  theta_u_cross_max.first = theta_u_cross_2;
240  theta_u_cross_max.second = u_ucross2;
241  }
242  else {
243  theta_u_cross_min.first = theta_u_cross_2;
244  theta_u_cross_min.second = u_ucross2;
245  theta_u_cross_max.first = theta_u_cross;
246  theta_u_cross_max.second = u_ucross;
247  }
248 
249  // Computing the two angles for which the v-axis is crossed
250  // u = u_c + r cos(theta)
251  // theta = acos((u - u_c) / r)
252  float theta_v_cross = std::acos((crossing_v - u_c) / radius);
253  theta_v_cross = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross);
254  float theta_v_cross_2 = -theta_v_cross;
255  // Computing the corresponding v-coordinates at which the v-axis is crossed
256  // v = v_c - radius sin(theta) because the v-axis is oriented towards the bottom
257  float v_vcross = v_c - (radius * std::sin(theta_v_cross));
258  float v_vcross2 = v_c - (radius * std::sin(theta_v_cross_2));
259  // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second
260  if (v_vcross < v_vcross2) {
261  theta_v_cross_min.first = theta_v_cross;
262  theta_v_cross_min.second = v_vcross;
263  theta_v_cross_max.first = theta_v_cross_2;
264  theta_v_cross_max.second = v_vcross2;
265  }
266  else {
267  theta_v_cross_min.first = theta_v_cross_2;
268  theta_v_cross_min.second = v_vcross2;
269  theta_v_cross_max.first = theta_v_cross;
270  theta_v_cross_max.second = v_vcross;
271  }
272 }
273 
285 void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi, const float &radius,
286  float &delta_theta)
287 {
288  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
289  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
290  float crossing_u = vmin_roi; // We cross the u-axis of the RoI at which v-coordinate
291  float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate
292  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v,
293  crossing_theta_u_min, crossing_theta_u_max,
294  crossing_theta_v_min, crossing_theta_v_max);
295  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
296  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
297  float u_umin = crossing_theta_u_min.second;
298  float u_umax = crossing_theta_u_max.second;
299  float v_vmin = crossing_theta_v_min.second;
300  float v_vmax = crossing_theta_v_max.second;
301  if ((u_umin < umin_roi) && (u_umax >= umin_roi) && (v_vmin < vmin_roi) && (v_vmax >= vmin_roi)) {
302  // The circle crosses only once each axis
303  //Case crossing once
304  delta_theta = theta_u_max - theta_v_max;
305  }
306  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax >= vmin_roi)) {
307  // The circle crosses twice each axis
308  //Case crossing twice
309  delta_theta = (theta_v_min - theta_u_min) + (theta_u_max - theta_v_max);
310  }
311  else if ((u_umin < umin_roi) && (u_umax < umin_roi) && (v_vmin >= vmin_roi) && (v_vmax >= vmin_roi)) {
312  // The circle crosses the u-axis outside the roi
313  // so it is equivalent to the case of crossing only the left border
314  //Case left only
315  computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
316  }
317  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmin_roi) && (v_vmax <= vmin_roi)) {
318  // The circle crosses the v-axis outside the roi
319  // so it is equivalent to the case of crossing only the top border
320  //Case top only
321  computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
322  }
323 }
324 
336 void computeIntersectionsTopRight(const float &u_c, const float &v_c, const float &vmin_roi, const float &umax_roi, const float &radius,
337  float &delta_theta)
338 {
339  const int val_2 = 2;
340  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
341  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
342  computePerpendicularAxesInters(u_c, v_c, radius, vmin_roi, umax_roi,
343  crossing_theta_u_min, crossing_theta_u_max,
344  crossing_theta_v_min, crossing_theta_v_max);
345  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
346  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
347  float u_umin = crossing_theta_u_min.second;
348  float u_umax = crossing_theta_u_max.second;
349  float v_vmin = crossing_theta_v_min.second;
350  float v_vmax = crossing_theta_v_max.second;
351  if ((u_umin <= umax_roi) && (v_vmin < vmin_roi) && (u_umax >= umax_roi) && (v_vmax >= vmin_roi)) {
352  // The circle crosses only once each axis and the center is below the top border
353  //Case crossing once
354  delta_theta = theta_v_max - theta_u_min;
355  if (delta_theta < 0) {
356  // The arc cannot be negative
357  delta_theta += 2.f * M_PI_FLOAT;
358  }
359  }
360  else if ((u_umin <= umax_roi) && (v_vmin >= vmin_roi) && (u_umax <= umax_roi) && (v_vmax >= vmin_roi)) {
361  // The circle crosses twice each axis
362  //Case crossing twice
363  delta_theta = (val_2 * M_PI_FLOAT) - ((theta_u_min - theta_u_max) + (theta_v_min - theta_v_max));
364  }
365  else if ((u_umin >= umax_roi) && (v_vmin >= vmin_roi) && (u_umax >= umax_roi) && (v_vmax >= vmin_roi)) {
366  // The circle crosses the u-axis outside the roi
367  // so it is equivalent to the case of crossing only the right border
368  //Case crossing right only
369  computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
370  }
371  else if ((u_umin <= umax_roi) && (v_vmin <= vmin_roi) && (u_umax <= umax_roi) && (v_vmax <= vmin_roi)) {
372  // The circle crosses the v-axis outside the roi
373  // so it is equivalent to the case of crossing only the top border
374  //Case crossing top only
375  computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
376  }
377 }
378 
390 void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmax_roi, const float &radius,
391  float &delta_theta)
392 {
393  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
394  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
395  float crossing_u = vmax_roi; // We cross the u-axis of the RoI at which v-coordinate
396  float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate
397  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v,
398  crossing_theta_u_min, crossing_theta_u_max,
399  crossing_theta_v_min, crossing_theta_v_max);
400  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
401  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
402  float u_umin = crossing_theta_u_min.second;
403  float u_umax = crossing_theta_u_max.second;
404  float v_vmin = crossing_theta_v_min.second;
405  float v_vmax = crossing_theta_v_max.second;
406  if ((u_umin < umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmax_roi) && (v_vmax > vmax_roi)) {
407  // The circle crosses only once each axis
408  //Case crossing once
409  delta_theta = theta_v_min - theta_u_max;
410  }
411  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
412  // The circle crosses twice each axis
413  //Case crossing twice
414  delta_theta = (theta_v_min - theta_u_max) + (theta_u_min - theta_v_max);
415  }
416  else if ((u_umin < umin_roi) && (u_umax < umin_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
417  // The circle crosses the u-axis outside the roi
418  // so it is equivalent to the case of crossing only the left border
419  //Case left only
420  computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
421  }
422  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin >= vmax_roi) && (v_vmax >= vmax_roi)) {
423  // The circle crosses the v-axis outside the roi
424  // so it is equivalent to the case of crossing only the bottom border
425  //Case bottom only
426  computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
427  }
428 }
429 
441 void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const float &vmax_roi, const float &umax_roi, const float &radius,
442  float &delta_theta)
443 {
444  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
445  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
446  float crossing_u = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
447  float crossing_v = umax_roi; // We cross the v-axis of the RoI at the maximum u-coordinate of the RoI
448  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v,
449  crossing_theta_u_min, crossing_theta_u_max,
450  crossing_theta_v_min, crossing_theta_v_max);
451  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
452  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
453  float u_umin = crossing_theta_u_min.second;
454  float u_umax = crossing_theta_u_max.second;
455  float v_vmin = crossing_theta_v_min.second;
456  float v_vmax = crossing_theta_v_max.second;
457  if ((u_umin <= umax_roi) && (u_umax > umax_roi) && (v_vmin <= vmax_roi) && (v_vmax > vmax_roi)) {
458  // The circle crosses only once each axis
459  //Case crossing once
460  delta_theta = theta_u_min - theta_v_min;
461  if (delta_theta < 0) {
462  // An arc length cannot be negative it means that theta_u_max was comprise in the bottom left quadrant of the circle
463  delta_theta += 2.f * M_PI_FLOAT;
464  }
465  }
466  else if ((u_umin <= umax_roi) && (u_umax <= umax_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
467  // The circle crosses twice each axis
468  //Case crossing twice
469  delta_theta = (2.f * M_PI_FLOAT) - ((theta_v_min - theta_v_max) + (theta_u_max - theta_u_min));
470  }
471  else if ((u_umin > umax_roi) && (u_umax > umax_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
472  // The circle crosses the u-axis outside the roi
473  // so it is equivalent to the case of crossing only the right border
474  //Case left only
475  computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
476  }
477  else if ((u_umin <= umax_roi) && (u_umax <= umax_roi) && (v_vmin > vmax_roi) && (v_vmax > vmax_roi)) {
478  // The circle crosses the v-axis outside the roi
479  // so it is equivalent to the case of crossing only the bottom border
480  //Case bottom only
481  computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
482  }
483 }
484 
497 void computeIntersTopLeftBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi,
498  const float &vmax_roi, const float &radius, float &delta_theta)
499 {
500  // Computing the intersections with the top and left axes
501  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
502  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
503  float crossing_u_top = vmin_roi; // We cross the u-axis of the top axis of the RoI at the minimum v-coordinate of the RoI
504  float crossing_v = umin_roi; // We cross the v-axis of the RoI at the minimum u-coordinate of the RoI
505  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_top, crossing_v,
506  crossing_theta_u_min, crossing_theta_u_max,
507  crossing_theta_v_min, crossing_theta_v_max);
508  float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
509  float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
510  float u_umin_top = crossing_theta_u_min.second;
511  float u_umax_top = crossing_theta_u_max.second;
512  float v_vmin = crossing_theta_v_min.second;
513  float v_vmax = crossing_theta_v_max.second;
514 
515  // Computing the intersections with the bottom and left axes
516  float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
517  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_bottom, crossing_v,
518  crossing_theta_u_min, crossing_theta_u_max,
519  crossing_theta_v_min, crossing_theta_v_max);
520  float theta_u_min_bottom = crossing_theta_u_min.first;
521  float theta_u_max_bottom = crossing_theta_u_max.first;
522  float u_umin_bottom = crossing_theta_u_min.second;
523  float u_umax_bottom = crossing_theta_u_max.second;
524  if ((u_umin_top >= umin_roi) && (u_umin_bottom >= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
525  // case intersection top + left + bottom twice
526  delta_theta = (theta_v_min - theta_u_min_top) + (theta_u_max_top - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max);
527  }
528  else if ((u_umin_top <= umin_roi) && (v_vmin <= vmin_roi) && (u_umin_bottom <= umin_roi) && (v_vmax >= vmax_roi)) {
529  // case intersection top and bottom
530  delta_theta = (theta_u_max_top - theta_u_max_bottom);
531  }
532  else if ((u_umax_top <= umin_roi) && (u_umax_bottom <= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
533  // case left only
534  computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
535  }
536  else if ((u_umax_bottom > umin_roi) && (v_vmin >= vmin_roi)) {
537  // case bottom/left corner
538  computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
539  }
540  else if ((u_umax_top > umin_roi) && (v_vmax <= vmax_roi)) {
541  // case top/left corner
542  computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
543  }
544 }
545 
558 void computeIntersTopRightBottom(const float &u_c, const float &v_c, const float &umax_roi, const float &vmin_roi, const float &vmax_roi,
559  const float &radius, float &delta_theta)
560 {
561  // Computing the intersections with the top and right axes
562  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
563  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
564  float crossing_u_top = vmin_roi; // We cross the u-axis of the top axis of the RoI at the minimum v-coordinate of the RoI
565  float crossing_v = umax_roi; // We cross the v-axis of the right axis of the RoI at the maximum u-coordinate of the RoI
566  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_top, crossing_v,
567  crossing_theta_u_min, crossing_theta_u_max,
568  crossing_theta_v_min, crossing_theta_v_max);
569  float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
570  float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
571  float u_umin_top = crossing_theta_u_min.second;
572  float u_umax_top = crossing_theta_u_max.second;
573  float v_vmin = crossing_theta_v_min.second;
574  float v_vmax = crossing_theta_v_max.second;
575 
576  // Computing the intersections with the bottom and right axes
577  float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
578  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_bottom, crossing_v,
579  crossing_theta_u_min, crossing_theta_u_max,
580  crossing_theta_v_min, crossing_theta_v_max);
581  float theta_u_min_bottom = crossing_theta_u_min.first;
582  float theta_u_max_bottom = crossing_theta_u_max.first;
583  float u_umin_bottom = crossing_theta_u_min.second;
584  float u_umax_bottom = crossing_theta_u_max.second;
585  bool crossOnceTopHor = (u_umin_top <= umax_roi) && (u_umax_top > umax_roi);
586  bool dontCrossVert = (v_vmin <= vmin_roi) && (v_vmax >= vmax_roi);
587  bool crossOnceBotHor = (u_umin_bottom <= umax_roi) && (u_umax_bottom > umax_roi);
588  if ((u_umax_top <= umax_roi) && (u_umax_bottom <= umax_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
589  // case intersection top + right + bottom twice
590  delta_theta = (2.f * M_PI_FLOAT) - ((theta_u_min_top - theta_u_max_top) + (theta_v_min - theta_v_max) + (theta_u_max_bottom - theta_u_min_bottom));
591  }
592  else if (crossOnceTopHor && crossOnceBotHor && dontCrossVert) {
593  // case intersection top and bottom
594  delta_theta = (theta_u_max_top - theta_u_max_bottom);
595  }
596  else if ((u_umin_top >= umax_roi) && (u_umin_bottom >= umax_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
597  // case right only
598  computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
599  }
600  else if ((u_umin_bottom <= umax_roi) && (v_vmin >= vmin_roi)) {
601  // case bottom/right corner
602  computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
603  }
604  else if ((u_umin_top <= umax_roi) && (v_vmax <= vmax_roi)) {
605  // case top/right corner
606  computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
607  }
608 }
609 
621 void computeIntersTopBottomOnly(const float &u_c, const float &v_c, const float &vmin_roi, const float &vmax_roi, const float &radius,
622  float &delta_theta)
623 {
624  // Computing the two angles for which the u-axis is crossed at the top of the RoI
625  // v = vc - r sin(theta) because the v-axis goes down
626  // theta = asin((vc - vmin_roi)/r)
627  float theta_u_cross_top = std::asin((v_c - vmin_roi) / radius);
628  theta_u_cross_top = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross_top);
629  float theta_u_cross_top_2 = 0.f;
630  if (theta_u_cross_top > 0) {
631  theta_u_cross_top_2 = M_PI_FLOAT - theta_u_cross_top;
632  }
633  else {
634  theta_u_cross_top_2 = -M_PI_FLOAT - theta_u_cross_top;
635  }
636 
637  // Computing the corresponding u-coordinates at which the u-axis is crossed
638  float u_ucross_top = u_c + (radius * std::cos(theta_u_cross_top));
639  float u_ucross_top_2 = u_c + (radius * std::cos(theta_u_cross_top_2));
640  // Sorting the outputs such as u(theta_u_cross_top_min) < u(theta_u_cross_top_max)
641  float theta_u_cross_top_min = 0.f, theta_u_cross_top_max = 0.f;
642  if (u_ucross_top < u_ucross_top_2) {
643  theta_u_cross_top_min = theta_u_cross_top;
644  theta_u_cross_top_max = theta_u_cross_top_2;
645  }
646  else {
647  theta_u_cross_top_min = theta_u_cross_top_2;
648  theta_u_cross_top_max = theta_u_cross_top;
649  }
650 
651  // Computing the two angles for which the u-axis is crossed at the bottom of the RoI
652  // v = vc - r sin(theta) because the v-axis goes down
653  // theta = asin((vc - vmax_roi)/r)
654  float theta_u_cross_bottom = std::asin((v_c - vmax_roi) / radius);
655  theta_u_cross_bottom = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross_bottom);
656  float theta_u_cross_bottom_2 = 0.f;
657  if (theta_u_cross_bottom > 0) {
658  theta_u_cross_bottom_2 = M_PI_FLOAT - theta_u_cross_bottom;
659  }
660  else {
661  theta_u_cross_bottom_2 = -M_PI_FLOAT - theta_u_cross_bottom;
662  }
663 
664  // Computing the corresponding u-coordinates at which the u-axis is crossed
665  float u_ucross_bottom = u_c + (radius * std::cos(theta_u_cross_bottom));
666  float u_ucross_bottom_2 = u_c + (radius * std::cos(theta_u_cross_bottom_2));
667 
668  // Sorting the outputs such as u(theta_u_cross_bottom_min) < u(theta_u_cross_bottom_max)
669  float theta_u_cross_bottom_min = 0.f, theta_u_cross_bottom_max = 0.f;
670  if (u_ucross_bottom < u_ucross_bottom_2) {
671  theta_u_cross_bottom_min = theta_u_cross_bottom;
672  theta_u_cross_bottom_max = theta_u_cross_bottom_2;
673  }
674  else {
675  theta_u_cross_bottom_min = theta_u_cross_bottom_2;
676  theta_u_cross_bottom_max = theta_u_cross_bottom;
677  }
678 
679  // Computing the the length of the angular interval of the circle when it intersects
680  // only with the top and bottom borders of the Region of Interest (RoI)
681  delta_theta = (2.f * M_PI_FLOAT) - ((theta_u_cross_top_min - theta_u_cross_top_max) + (theta_u_cross_bottom_max - theta_u_cross_bottom_min));
682 }
683 
696 void computeIntersLeftRightTop(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
697  const float &vmin_roi, const float &radius, float &delta_theta)
698 {
699  // Computing the intersections with the top and left axes
700  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
701  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
702  float crossing_u = vmin_roi; // We cross the u-axis of the RoI at the minimum v-coordinate of the RoI
703  float crossing_v_left = umin_roi; // We cross the v-axis of the left of the RoI at the minimum u-coordinate of the RoI
704  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_left,
705  crossing_theta_u_min, crossing_theta_u_max,
706  crossing_theta_v_min, crossing_theta_v_max);
707  float theta_u_min = crossing_theta_u_min.first;
708  float theta_u_max = crossing_theta_u_max.first;
709  float u_umin = crossing_theta_u_min.second;
710  float u_umax = crossing_theta_u_max.second;
711  float theta_v_min_left = crossing_theta_v_min.first;
712  float theta_v_max_left = crossing_theta_v_max.first;
713  float v_vmin_left = crossing_theta_v_min.second;
714  float v_vmax_left = crossing_theta_v_max.second;
715 
716  // Computing the intersections with the rigt and top axes
717  float crossing_v_right = umax_roi; // We cross the v-axis of the right of the RoI at the maximum u-coordinate of the RoI
718  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_right,
719  crossing_theta_u_min, crossing_theta_u_max,
720  crossing_theta_v_min, crossing_theta_v_max);
721  float theta_v_min_right = crossing_theta_v_min.first;
722  float theta_v_max_right = crossing_theta_v_max.first;
723  float v_vmin_right = crossing_theta_v_min.second;
724  float v_vmax_right = crossing_theta_v_max.second;
725 
726  if ((u_umin >= umin_roi) && (u_umax <= umax_roi) && (v_vmin_left >= vmin_roi) && (v_vmin_right >= vmin_roi)) {
727  // case intersection left + right + top twice
728  delta_theta = (theta_v_min_left - theta_u_min) + (theta_u_max - theta_v_min_right) + (theta_v_max_right - theta_v_max_left);
729  }
730  else if ((u_umin <= umin_roi) && (u_umax >= umax_roi) && (v_vmax_left >= vmin_roi) && (v_vmax_right >= vmin_roi)) {
731  // case intersection left + right
732  delta_theta = (theta_v_max_right - theta_v_max_left);
733  }
734  else if ((v_vmax_left <= vmin_roi) && (v_vmax_right <= vmin_roi) && (u_umin >= umin_roi) && (u_umax <= umax_roi)) {
735  // case top only
736  computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
737  }
738  else if ((u_umax >= umin_roi) && (v_vmax_left >= vmin_roi)) {
739  // case top/left corner
740  computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
741  }
742  else if ((u_umin <= umax_roi) && (v_vmax_right >= vmin_roi)) {
743  // case top/right corner
744  computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
745  }
746 }
747 
760 void computeIntersLeftRightBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
761  const float &vmax_roi, const float &radius, float &delta_theta)
762 {
763  // Computing the intersections with the bottom and left axes
764  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
765  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
766  float crossing_u = vmax_roi; // We cross the u-axis of the bottom axis of the RoI at the maximum v-coordinate of the RoI
767  float crossing_v_left = umin_roi; // We cross the v-axis of the left of the RoI at the minimum u-coordinate of the RoI
768  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_left,
769  crossing_theta_u_min, crossing_theta_u_max,
770  crossing_theta_v_min, crossing_theta_v_max);
771  float theta_u_min = crossing_theta_u_min.first;
772  float theta_u_max = crossing_theta_u_max.first;
773  float u_umin = crossing_theta_u_min.second;
774  float u_umax = crossing_theta_u_max.second;
775  float theta_v_min_left = crossing_theta_v_min.first;
776  float theta_v_max_left = crossing_theta_v_max.first;
777  float v_vmin_left = crossing_theta_v_min.second;
778  // --comment: float v_vmax_left equals crossing_theta_v_max dot second
779 
780  // Computing the intersections with the bottom and right axes
781  float crossing_v_right = umax_roi; // We cross the v-axis of the right of the RoI at the maximum u-coordinate of the RoI
782  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_right,
783  crossing_theta_u_min, crossing_theta_u_max,
784  crossing_theta_v_min, crossing_theta_v_max);
785  float theta_v_min_right = crossing_theta_v_min.first;
786  float theta_v_max_right = crossing_theta_v_max.first;
787  float v_vmin_right = crossing_theta_v_min.second;
788  // --comment: float v_vmax_right equals crossing_theta_v_max dot second
789 
790  if ((u_umin >= umin_roi) && (u_umax <= umax_roi) && (v_vmin_left <= vmax_roi) && (v_vmin_right <= vmax_roi)) {
791  // case intersection left + right + bottom twice
792  delta_theta = (theta_v_min_left - theta_v_min_right) + (theta_v_max_right - theta_u_max) + (theta_u_min - theta_v_max_left);
793  }
794  else if ((u_umin <= umin_roi) && (u_umax >= umax_roi) && (v_vmin_left <= vmax_roi) && (v_vmin_right <= vmax_roi)) {
795  // case intersection left + right
796  delta_theta = (theta_v_min_left - theta_v_min_right);
797  }
798  else if ((v_vmin_left >= vmax_roi) && (v_vmin_right >= vmax_roi) && (u_umin >= umin_roi) && (u_umax <= umax_roi)) {
799  // case bottom only
800  computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
801  }
802  else if ((u_umax >= umin_roi) && (v_vmin_right >= vmax_roi)) {
803  // case bottom/left corner
804  computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
805  }
806  else if ((u_umin <= umax_roi) && (v_vmin_right <= vmax_roi)) {
807  // case bottom/right corner
808  computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
809  }
810 }
811 
823 void computeIntersectionsLeftRight(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi, const float &radius,
824  float &delta_theta)
825 {
826  // Computing the two angles for which the v-axis is crossed at the left of the RoI
827  // umin_roi = u_c + r cos(theta)
828  // theta = acos((umin_roi - u_c)/r)
829  // theta_min = -theta_max
830  float theta_v_cross_left = std::acos((umin_roi - u_c) / radius);
831  theta_v_cross_left = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross_left);
832  float theta_v_cross_left_2 = -theta_v_cross_left;
833 
834  // Computing the corresponding v-coordinates at which the v-axis is crossed
835  float v_vcross_left = v_c - (radius * std::sin(theta_v_cross_left));
836  float v_vcross_left_2 = v_c - (radius * std::sin(theta_v_cross_left_2));
837  // Sorting the outputs such as v(theta_v_cross_left_min) < v(theta_v_cross_left_max)
838  float theta_v_cross_left_min = 0.f, theta_v_cross_left_max = 0.f;
839  if (v_vcross_left < v_vcross_left_2) {
840  theta_v_cross_left_min = theta_v_cross_left;
841  theta_v_cross_left_max = theta_v_cross_left_2;
842  }
843  else {
844  theta_v_cross_left_min = theta_v_cross_left_2;
845  theta_v_cross_left_max = theta_v_cross_left;
846  }
847 
848  // Computing the two angles for which the v-axis is crossed at the right of the RoI
849  // umax_roi = u_c + r cos(theta)
850  // theta = acos((umin_roi - u_c)/r)
851  // theta_min = -theta_max
852  float theta_v_cross_right = std::acos((umax_roi - u_c) / radius);
853  theta_v_cross_right = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross_right);
854  float theta_v_cross_right_2 = -theta_v_cross_right;
855 
856  // Computing the corresponding v-coordinates at which the v-axis is crossed
857  float v_vcross_right = v_c - (radius * std::sin(theta_v_cross_right));
858  float v_vcross_right_2 = v_c - (radius * std::sin(theta_v_cross_right_2));
859 
860  // Sorting the outputs such as v(theta_v_cross_right_min) < v(theta_v_cross_right_max)
861  float theta_v_cross_right_min = 0.f, theta_v_cross_right_max = 0.f;
862  if (v_vcross_right < v_vcross_right_2) {
863  theta_v_cross_right_min = theta_v_cross_right;
864  theta_v_cross_right_max = theta_v_cross_right_2;
865  }
866  else {
867  theta_v_cross_right_min = theta_v_cross_right_2;
868  theta_v_cross_right_max = theta_v_cross_right;
869  }
870 
871  // Computing the the length of the angular interval of the circle when it intersects
872  // only with the top and bottom borders of the Region of Interest (RoI)
873  delta_theta = (theta_v_cross_left_min - theta_v_cross_right_min) + (theta_v_cross_right_max - theta_v_cross_left_max);
874 }
875 
876 
890 void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
891  const float &vmin_roi, const float &vmax_roi, const float &radius, float &delta_theta)
892 {
893  // Computing the intersections with the top and left axes
894  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
895  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
896  float crossing_u_top = vmin_roi; // We cross the u-axis of the top axis of the RoI at the minimum v-coordinate of the RoI
897  float crossing_v_left = umin_roi; // We cross the v-axis of the left of the RoI at the minimum u-coordinate of the RoI
898  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_top, crossing_v_left,
899  crossing_theta_u_min, crossing_theta_u_max,
900  crossing_theta_v_min, crossing_theta_v_max);
901  float theta_u_min_top = crossing_theta_u_min.first;
902  float theta_u_max_top = crossing_theta_u_max.first;
903  float theta_v_min_left = crossing_theta_v_min.first;
904  float theta_v_max_left = crossing_theta_v_max.first;
905 
906  // Computing the intersections with the bottom and right axes
907  float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
908  float crossing_v_right = umax_roi; // We cross the v-axis of the right of the RoI at the maximum u-coordinate of the RoI
909  computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_bottom, crossing_v_right,
910  crossing_theta_u_min, crossing_theta_u_max,
911  crossing_theta_v_min, crossing_theta_v_max);
912  float theta_u_min_bottom = crossing_theta_u_min.first;
913  float theta_u_max_bottom = crossing_theta_u_max.first;
914  float theta_v_min_right = crossing_theta_v_min.first;
915  float theta_v_max_right = crossing_theta_v_max.first;
916  delta_theta = (theta_v_min_left - theta_u_min_top) + (theta_u_max_top - theta_v_min_right);
917  delta_theta += (theta_v_max_right - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max_left);
918 }
919 
920 float vpImageCircle::computeAngularCoverageInRoI(const vpRect &roi, const float &roundingTolerance) const
921 {
922  float delta_theta = 0.f;
923  vpImagePoint center = m_center;
924  float u_c = static_cast<float>(center.get_u());
925  float v_c = static_cast<float>(center.get_v());
926  float radius = m_radius;
927  float roi_w = static_cast<float>(roi.getWidth());
928  float roi_h = static_cast<float>(roi.getHeight());
929  vpImagePoint topLeft = roi.getTopLeft();
930  float umin_roi = static_cast<float>(topLeft.get_u());
931  float vmin_roi = static_cast<float>(topLeft.get_v());
932  float umax_roi = umin_roi + roi_w;
933  float vmax_roi = vmin_roi + roi_h;
934  bool touchLeftBorder = (u_c - radius) <= umin_roi;
935  bool touchRightBorder = (u_c + radius) >= umax_roi;
936  bool touchTopBorder = (v_c - radius) <= vmin_roi;
937  bool touchBottomBorder = (v_c + radius) >= vmax_roi;
938  bool isHorizontallyOK = ((!touchLeftBorder) && (!touchRightBorder));
939  bool isVerticallyOK = ((!touchTopBorder) && (!touchBottomBorder));
940  if (isHorizontallyOK && isVerticallyOK && roi.isInside(m_center)) {
941  // Easy case
942  // The circle has its center in the image and its radius is not too great
943  // to make it fully contained in the RoI
944  delta_theta = 2.f * M_PI_FLOAT;
945  }
946  else if (touchBottomBorder && (!touchLeftBorder) && (!touchRightBorder) && (!touchTopBorder)) {
947  // Touches/intersects only the bottom border of the RoI
948  computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
949  }
950  else if ((!touchBottomBorder) && touchLeftBorder && (!touchRightBorder) && (!touchTopBorder)) {
951  // Touches/intersects only the left border of the RoI
952  computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
953  }
954  else if ((!touchBottomBorder) && (!touchLeftBorder) && touchRightBorder && (!touchTopBorder)) {
955  // Touches/intersects only the right border of the RoI
956  computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
957  }
958  else if ((!touchBottomBorder) && (!touchLeftBorder) && (!touchRightBorder) && touchTopBorder) {
959  // Touches/intersects only the top border of the RoI
960  computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
961  }
962  else if (touchBottomBorder && touchLeftBorder && (!touchRightBorder) && (!touchTopBorder)) {
963  // Touches/intersects the bottom and left borders of the RoI
964  computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
965  }
966  else if (touchBottomBorder && (!touchLeftBorder) && touchRightBorder && (!touchTopBorder)) {
967  // Touches/intersects the bottom and right borders of the RoI
968  computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
969  }
970  else if ((!touchBottomBorder) && touchLeftBorder && (!touchRightBorder) && touchTopBorder) {
971  // Touches/intersects the top and left borders of the RoI
972  computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
973  }
974  else if ((!touchBottomBorder) && (!touchLeftBorder) && touchRightBorder && touchTopBorder) {
975  // Touches/intersects the top and right borders of the RoI
976  computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
977  }
978  else if (touchBottomBorder && touchTopBorder && touchLeftBorder && (!touchRightBorder)) {
979  // Touches/intersects the top, left and bottom borders of the RoI
980  computeIntersTopLeftBottom(u_c, v_c, umin_roi, vmin_roi, vmax_roi, radius, delta_theta);
981  }
982  else if (touchBottomBorder && touchTopBorder && (!touchLeftBorder) && touchRightBorder) {
983  // Touches/intersects the top, right and bottom borders of the RoI
984  computeIntersTopRightBottom(u_c, v_c, umax_roi, vmin_roi, vmax_roi, radius, delta_theta);
985  }
986  else if (touchBottomBorder && touchTopBorder && (!touchLeftBorder) && (!touchRightBorder)) {
987  // Touches/intersects the top and bottom borders of the RoI
988  computeIntersTopBottomOnly(u_c, v_c, vmin_roi, vmax_roi, radius, delta_theta);
989  }
990  else if ((!touchBottomBorder) && touchTopBorder && touchLeftBorder && touchRightBorder) {
991  // Touches/intersects the top, left and right borders of the RoI
992  computeIntersLeftRightTop(u_c, v_c, umin_roi, umax_roi, vmin_roi, radius, delta_theta);
993  }
994  else if (touchBottomBorder && (!touchTopBorder) && touchLeftBorder && touchRightBorder) {
995  // Touches/intersects the bottom, left and right borders of the RoI
996  computeIntersLeftRightBottom(u_c, v_c, umin_roi, umax_roi, vmax_roi, radius, delta_theta);
997  }
998  else if (touchLeftBorder && touchRightBorder && (!touchTopBorder) && (!touchBottomBorder)) {
999  // Touches/intersects the bottom, left and right borders of the RoI
1000  computeIntersectionsLeftRight(u_c, v_c, umin_roi, umax_roi, radius, delta_theta);
1001  }
1002  else if (touchLeftBorder && touchRightBorder && touchTopBorder && touchBottomBorder) {
1003  // Touches/intersects each axis
1004  computeIntersectionsAllAxes(u_c, v_c, umin_roi, umax_roi, vmin_roi, vmax_roi, radius, delta_theta);
1005  }
1006  else {
1007  std::cerr << "touchLeft = " << (touchLeftBorder ? "true" : "false") << "\ttouchRight = " << (touchRightBorder ? "true" : "false") << std::endl;
1008  std::cerr << "touchTop = " << (touchTopBorder ? "true" : "false") << "\ttouchBottom = " << (touchBottomBorder ? "true" : "false") << std::endl;
1009  std::cerr << "u_c = " << u_c << "\tv_c = " << v_c << "\tradius = " << radius << std::endl;
1010  std::cerr << "umin_roi = " << umin_roi << "\tumax_roi = " << umax_roi << std::endl;
1011  std::cerr << "vmin_roi = " << vmin_roi << "\tvmax_roi = " << vmax_roi << std::endl << std::flush;
1012  throw(vpException(vpException::fatalError, "This case should never happen. Please contact Inria to make fix the problem"));
1013  }
1014 
1015  if ((delta_theta < 0) || (delta_theta >(2.f * M_PI_FLOAT))) { // Needed since M_PI_FLOAT is used
1016  float rest = vpMath::modulo(delta_theta, 2.f * M_PI_FLOAT);
1017  if ((rest < roundingTolerance) && ((delta_theta < -M_PI_FLOAT) || (delta_theta > M_PI_FLOAT))) {
1018  // If the angle is a negative multiple of 2.f * M_PI_FLOAT we consider it to be 2.f * M_PI_FLOAT
1019  delta_theta = 2.f * M_PI_FLOAT;
1020  }
1021  else {
1022  //Otherwise, it corresponds to delta_theta modulo 2.f * M_PI_FLOAT
1023  delta_theta = rest;
1024  }
1025  }
1026 
1027  return delta_theta;
1028 }
1029 
1030 float vpImageCircle::computeArcLengthInRoI(const vpRect &roi, const float &roundingTolerance) const
1031 {
1032  float delta_theta = computeAngularCoverageInRoI(roi, roundingTolerance);
1033  return delta_theta * m_radius;
1034 }
1035 
1036 #if (VISP_CXX_STANDARD == VISP_CXX_STANDARD_98)
1037 namespace
1038 {
1039 // Increment the counter if the considered pixel (x, y) is in the mask image
1040 void incrementIfIsInMask(const vpImage<bool> &mask, const int &width, const int &height, const int &x, const int &y,
1041  unsigned int &count)
1042 {
1043  if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1044  // The pixel is outside the limit of the mask
1045  return;
1046  }
1047  if (mask[y][x]) {
1048  // Increment only if the pixel value of the mask is true
1049  ++count;
1050  }
1051 }
1052 }
1053 #endif
1054 
1055 unsigned int vpImageCircle::computePixelsInMask(const vpImage<bool> &mask) const
1056 {
1057  const float xm = static_cast<float>(m_center.get_u()), ym = static_cast<float>(m_center.get_v());
1058  const float r_float = static_cast<float>(m_radius);
1059  const int width = mask.getWidth();
1060  const int height = mask.getHeight();
1061 
1062 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
1063  // Increment the counter if the considered pixel (x, y) is in the mask image
1064  auto incrementIfIsInMask = [](const vpImage<bool> &mask, const int &width, const int &height, const int &x, const int &y,
1065  unsigned int &count) {
1066  if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1067  // The pixel is outside the limit of the mask
1068  return;
1069  }
1070  if (mask[y][x]) {
1071  // Increment only if the pixel value of the mask is true
1072  ++count;
1073  }
1074  };
1075 #endif
1076  unsigned int count = 0; // Count the number of pixels of the circle whose value in the mask is true
1077 
1078  const float thetaStop = M_PI_2_FLOAT;
1079  float theta = 0;
1080  int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
1081  int y1 = 0, y2 = 0, y3 = 0, y4 = 0;
1082  while (theta < thetaStop) {
1083  float cos_theta = std::cos(theta);
1084  float sin_theta = std::sin(theta);
1085  float rcos_pos = r_float * cos_theta;
1086  float rsin_pos = r_float * sin_theta;
1087  x1 = static_cast<int>(xm + rcos_pos); // theta
1088  y1 = static_cast<int>(ym + rsin_pos); // theta
1089  x2 = static_cast<int>(xm - rsin_pos); // theta + pi
1090  y2 = static_cast<int>(ym + rcos_pos); // theta + pi
1091  x3 = static_cast<int>(xm - rcos_pos); // theta + pi/2
1092  y3 = static_cast<int>(ym - rsin_pos); // theta + pi/2
1093  x4 = static_cast<int>(xm + rsin_pos); // theta + pi
1094  y4 = static_cast<int>(ym - rcos_pos); // theta + pi
1095  incrementIfIsInMask(mask, width, height, x1, y1, count);
1096  incrementIfIsInMask(mask, width, height, x2, y2, count);
1097  incrementIfIsInMask(mask, width, height, x3, y3, count);
1098  incrementIfIsInMask(mask, width, height, x4, y4, count);
1099 
1100  // Looking for dtheta such as either x or 1 increments of 1 pix exactly
1101  // Using series expansion, we get that if we want to have an increment of
1102  // 1 pixel for the derivative along x (resp. y), we have to respect the
1103  // following formulae
1104  float dthetaCosPos = 1.f / (r_float * cos_theta);
1105  float dthetaCosNeg = -1.f / (r_float * cos_theta);
1106  float dthetaSinPos = 1.f / (r_float * sin_theta);
1107  float dthetaSinNeg = -1.f / (r_float * sin_theta);
1108  float dthetaPos = 0.f;
1109  if ((sin_theta < 0.f) && (cos_theta > 0.f)) {
1110  // --comment: dTheta lesseq -1/r sin(theta) and dTheta lesseq 1/r cos(theta)
1111  dthetaPos = std::min<float>(dthetaCosPos, dthetaSinNeg);
1112  }
1113  else if ((sin_theta > 0.f) && (cos_theta < 0.f)) {
1114  // --comment: dTheta lesseq 1/r sin(theta) and dTheta lesseq -1/r cos(theta)
1115  dthetaPos = std::min<float>(dthetaCosNeg, dthetaSinPos);
1116  }
1117  else if ((sin_theta < 0.f) && (cos_theta < 0.f)) {
1118  // --comment: dTheta lesseq -1/r sin(theta) and dTheta lesseq -1/r cos(theta)
1119  dthetaPos = std::min<float>(dthetaCosNeg, dthetaSinNeg);
1120  }
1121  else if ((sin_theta > 0.f) && (cos_theta > 0.f)) {
1122  // --comment: dTheta lesseq 1/r sin(theta) and dTheta lesseq 1/r cos(theta)
1123  dthetaPos = std::min<float>(dthetaCosPos, dthetaSinPos);
1124  }
1125  else if (vpMath::equal(sin_theta, 0.f) && (!vpMath::equal(cos_theta, 0.f))) {
1126  // --comment: dTheta eq -1 / r cos(theta) or dTheta eq 1 / r cos(theta)
1127  if (cos_theta > 0.f) {
1128  dthetaPos = dthetaCosNeg;
1129  }
1130  else {
1131  dthetaPos = dthetaCosPos;
1132  }
1133  }
1134  else if ((!vpMath::equal(sin_theta, 0.f)) && vpMath::equal(cos_theta, 0.f)) {
1135  // --comment: dTheta eq -1 / r sin(theta) or dTheta eq 1 / r sin(theta)
1136  if (sin_theta > 0.f) {
1137  dthetaPos = dthetaSinNeg;
1138  }
1139  else {
1140  dthetaPos = dthetaSinPos;
1141  }
1142  }
1143  theta += dthetaPos;
1144  }
1145  return count;
1146 }
1147 
1149 {
1150  return m_center;
1151 }
1152 
1154 {
1155  return m_radius;
1156 }
1157 
1159 {
1160  vpRect bbox(m_center - vpImagePoint(m_radius, m_radius), 2 * m_radius, 2 * m_radius);
1161  return bbox;
1162 }
1163 
1165 {
1166  const int val_4 = 4;
1167  return (m_radius * m_radius) / val_4;
1168 }
1169 
1171 {
1172  const int val_4 = 4;
1173  return (m_radius * m_radius) / val_4;
1174 }
1175 
1177 {
1178  return 0.;
1179 }
1180 END_VISP_NAMESPACE
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ fatalError
Fatal error.
Definition: vpException.h:72
float computeAngularCoverageInRoI(const vpRect &roi, const float &roundingTolerance=0.001f) const
float getRadius() const
float get_n11() const
vpRect getBBox() const
vpImagePoint getCenter() const
float get_n02() const
float computeArcLengthInRoI(const vpRect &roi, const float &roundingTolerance=0.001f) const
float get_n20() const
unsigned int computePixelsInMask(const vpImage< bool > &mask) const
Count the number of pixels of the circle whose value in the mask is true.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_u() const
Definition: vpImagePoint.h:136
double get_v() const
Definition: vpImagePoint.h:147
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getHeight() const
Definition: vpImage.h:181
static float getAngleBetweenMinPiAndPi(const float &theta)
Definition: vpMath.h:139
static bool equal(double x, double y, double threshold=0.001)
Definition: vpMath.h:459
static float modulo(const float &value, const float &modulo)
Gives the rest of value divided by modulo when the quotient can only be an integer.
Definition: vpMath.h:177
Defines a rectangle in the plane.
Definition: vpRect.h:79
double getWidth() const
Definition: vpRect.h:227
bool isInside(const vpImagePoint &ip) const
Definition: vpRect.cpp:120
vpImagePoint getTopLeft() const
Definition: vpRect.h:199
double getHeight() const
Definition: vpRect.h:166