Visual Servoing Platform  version 3.6.1 under development (2024-04-23)
vpImageCircle.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 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 
38  : m_center()
39  , m_radius(0.)
40 {
41 
42 }
43 
44 vpImageCircle::vpImageCircle(const vpImagePoint &center, const float &radius)
45  : m_center(center)
46  , m_radius(radius)
47 {
48 
49 }
50 
51 #ifdef HAVE_OPENCV_CORE
52 vpImageCircle::vpImageCircle(const cv::Vec3f &vec)
53  : m_center(vec[1], vec[0])
54  , m_radius(vec[2])
55 {
56 
57 }
58 #endif
59 
69 void computeIntersectionsLeftBorderOnly(const float &u_c, const float &umin_roi, const float &radius,
70  float &delta_theta)
71 {
72  // --comment: umin_roi = u_c + r cos(theta)
73  // --comment: theta = acos of of umin_roi - u_c endof / r endof
74  float theta1 = std::acos((umin_roi - u_c) / radius);
75  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
76  float theta2 = -1.f * theta1;
77  float theta_min = std::min<float>(theta1, theta2);
78  float theta_max = std::max<float>(theta1, theta2);
79  delta_theta = theta_max - theta_min;
80  if ((u_c < umin_roi) && (std::abs(delta_theta - (2 * M_PIf)) < (2.f * std::numeric_limits<float>::epsilon()))) {
81  delta_theta = 0.f;
82  }
83 }
84 
94 void computeIntersectionsRightBorderOnly(const float &u_c, const float &umax_roi, const float &radius,
95  float &delta_theta)
96 {
97  // --comment: u = u_c + r cos(theta)
98  // --comment: theta = acos of of u - u_c endof / r endof
99  float theta1 = std::acos((umax_roi - u_c) / radius);
100  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
101  float theta2 = -1.f * theta1;
102  float theta_min = std::min<float>(theta1, theta2);
103  float theta_max = std::max<float>(theta1, theta2);
104  delta_theta = (2.f * M_PIf) - (theta_max - theta_min);
105  if ((u_c > umax_roi) && (std::abs(delta_theta - (2 * M_PIf)) < (2.f * std::numeric_limits<float>::epsilon()))) {
106  delta_theta = 0.f;
107  }
108 }
109 
119 void computeIntersectionsTopBorderOnly(const float &v_c, const float &vmin_roi, const float &radius,
120  float &delta_theta)
121 {
122  // v = vc - r sin(theta) because the v-axis goes down
123  // theta = asin((vc - v)/r)
124  float theta1 = std::asin((v_c - vmin_roi) / radius);
125  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
126 
127  float theta2 = 0.f;
128  if (theta1 >= 0.f) {
129  theta2 = M_PIf - theta1;
130  }
131  else {
132  theta2 = -theta1 - M_PIf;
133  }
134  float theta_min = std::min<float>(theta1, theta2);
135  float theta_max = std::max<float>(theta1, theta2);
136  if ((std::abs(theta_max - theta_min) * radius) < 1.f) {
137  // Between the maximum and minimum theta there is less than 1 pixel of difference
138  // It meens that the full circle is visible
139  delta_theta = 2.f * M_PIf;
140  }
141  else if (theta1 > 0.f) {
142  delta_theta = (2.f * M_PIf) - (theta_max - theta_min);
143  }
144  else {
145  delta_theta = theta_max - theta_min;
146  }
147  if ((v_c < vmin_roi) && (std::abs(delta_theta - (2 * M_PIf)) < (2.f * std::numeric_limits<float>::epsilon()))) {
148  delta_theta = 0.f;
149  }
150 }
151 
161 void computeIntersectionsBottomBorderOnly(const float &v_c, const float &vmax_roi, const float &radius,
162  float &delta_theta)
163 {
164  // v = vc - r sin(theta) because the v-axis goes down
165  // theta = asin((vc - v)/r)
166  float theta1 = std::asin((v_c - vmax_roi) / radius);
167  theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
168 
169  float theta2 = 0.f;
170  if (theta1 >= 0.f) {
171  theta2 = M_PIf - theta1;
172  }
173  else {
174  theta2 = -theta1 - M_PIf;
175  }
176  float theta_min = std::min<float>(theta1, theta2);
177  float theta_max = std::max<float>(theta1, theta2);
178  if ((std::abs(theta_max - theta_min) * radius) < 1.f) {
179  // Between the maximum and minimum theta there is less than 1 pixel of difference
180  // It meens that the full circle is visible
181  delta_theta = 2.f * M_PIf;
182  }
183  else if (theta1 > 0.f) {
184  delta_theta = theta_max - theta_min;
185  }
186  else {
187  delta_theta = (2.f * M_PIf) - (theta_max - theta_min);
188  }
189  if ((v_c > vmax_roi) && (std::abs(delta_theta - (2 * M_PIf)) < (2.f * std::numeric_limits<float>::epsilon()))) {
190  delta_theta = 0.f;
191  }
192 }
193 
208 void computePerpendicularAxesIntersections(const float &u_c, const float &v_c, const float &radius,
209  const float &crossing_u, const float &crossing_v,
210  std::pair<float, float> &theta_u_cross_min, std::pair<float, float> &theta_u_cross_max,
211  std::pair<float, float> &theta_v_cross_min, std::pair<float, float> &theta_v_cross_max)
212 {
213  // Computing the two angles for which the u-axis is crossed
214  // v = vc - r sin(theta) because the v-axis goes down
215  // theta = asin((vc - v)/r)
216  float theta_u_cross = std::asin((v_c - crossing_u) / radius);
217  theta_u_cross = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross);
218  float theta_u_cross_2 = 0.f;
219  if (theta_u_cross > 0) {
220  theta_u_cross_2 = M_PIf - theta_u_cross;
221  }
222  else {
223  theta_u_cross_2 = -M_PIf - theta_u_cross;
224  }
225  // Computing the corresponding u-coordinates at which the u-axis is crossed
226  float u_ucross = u_c + (radius * std::cos(theta_u_cross));
227  float u_ucross2 = u_c + (radius * std::cos(theta_u_cross_2));
228  // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second
229  if (u_ucross < u_ucross2) {
230  theta_u_cross_min.first = theta_u_cross;
231  theta_u_cross_min.second = u_ucross;
232  theta_u_cross_max.first = theta_u_cross_2;
233  theta_u_cross_max.second = u_ucross2;
234  }
235  else {
236  theta_u_cross_min.first = theta_u_cross_2;
237  theta_u_cross_min.second = u_ucross2;
238  theta_u_cross_max.first = theta_u_cross;
239  theta_u_cross_max.second = u_ucross;
240  }
241 
242  // Computing the two angles for which the v-axis is crossed
243  // u = u_c + r cos(theta)
244  // theta = acos((u - u_c) / r)
245  float theta_v_cross = std::acos((crossing_v - u_c) / radius);
246  theta_v_cross = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross);
247  float theta_v_cross_2 = -theta_v_cross;
248  // Computing the corresponding v-coordinates at which the v-axis is crossed
249  // v = v_c - radius sin(theta) because the v-axis is oriented towards the bottom
250  float v_vcross = v_c - (radius * std::sin(theta_v_cross));
251  float v_vcross2 = v_c - (radius * std::sin(theta_v_cross_2));
252  // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second
253  if (v_vcross < v_vcross2) {
254  theta_v_cross_min.first = theta_v_cross;
255  theta_v_cross_min.second = v_vcross;
256  theta_v_cross_max.first = theta_v_cross_2;
257  theta_v_cross_max.second = v_vcross2;
258  }
259  else {
260  theta_v_cross_min.first = theta_v_cross_2;
261  theta_v_cross_min.second = v_vcross2;
262  theta_v_cross_max.first = theta_v_cross;
263  theta_v_cross_max.second = v_vcross;
264  }
265 }
266 
278 void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi, const float &radius,
279  float &delta_theta)
280 {
281  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
282  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
283  float crossing_u = vmin_roi; // We cross the u-axis of the RoI at which v-coordinate
284  float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate
285  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v,
286  crossing_theta_u_min, crossing_theta_u_max,
287  crossing_theta_v_min, crossing_theta_v_max);
288  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
289  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
290  float u_umin = crossing_theta_u_min.second;
291  float u_umax = crossing_theta_u_max.second;
292  float v_vmin = crossing_theta_v_min.second;
293  float v_vmax = crossing_theta_v_max.second;
294  if ((u_umin < umin_roi) && (u_umax >= umin_roi) && (v_vmin < vmin_roi) && (v_vmax >= vmin_roi)) {
295  // The circle crosses only once each axis
296  //Case crossing once
297  delta_theta = theta_u_max - theta_v_max;
298  }
299  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax >= vmin_roi)) {
300  // The circle crosses twice each axis
301  //Case crossing twice
302  delta_theta = (theta_v_min - theta_u_min) + (theta_u_max - theta_v_max);
303  }
304  else if ((u_umin < umin_roi) && (u_umax < umin_roi) && (v_vmin >= vmin_roi) && (v_vmax >= vmin_roi)) {
305  // The circle crosses the u-axis outside the roi
306  // so it is equivalent to the case of crossing only the left border
307  //Case left only
308  computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta);
309  }
310  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmin_roi) && (v_vmax <= vmin_roi)) {
311  // The circle crosses the v-axis outside the roi
312  // so it is equivalent to the case of crossing only the top border
313  //Case top only
314  computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta);
315  }
316 }
317 
329 void computeIntersectionsTopRight(const float &u_c, const float &v_c, const float &vmin_roi, const float &umax_roi, const float &radius,
330  float &delta_theta)
331 {
332  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
333  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
334  computePerpendicularAxesIntersections(u_c, v_c, radius, vmin_roi, umax_roi,
335  crossing_theta_u_min, crossing_theta_u_max,
336  crossing_theta_v_min, crossing_theta_v_max);
337  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
338  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
339  float u_umin = crossing_theta_u_min.second;
340  float u_umax = crossing_theta_u_max.second;
341  float v_vmin = crossing_theta_v_min.second;
342  float v_vmax = crossing_theta_v_max.second;
343  if ((u_umin <= umax_roi) && (v_vmin < vmin_roi) && (u_umax >= umax_roi) && (v_vmax >= vmin_roi)) {
344  // The circle crosses only once each axis and the center is below the top border
345  //Case crossing once
346  delta_theta = theta_v_max - theta_u_min;
347  if (delta_theta < 0) {
348  // The arc cannot be negative
349  delta_theta += 2.f * M_PIf;
350  }
351  }
352  else if ((u_umin <= umax_roi) && (v_vmin >= vmin_roi) && (u_umax <= umax_roi) && (v_vmax >= vmin_roi)) {
353  // The circle crosses twice each axis
354  //Case crossing twice
355  delta_theta = (2 * M_PIf) - ((theta_u_min - theta_u_max) + (theta_v_min - theta_v_max));
356  }
357  else if ((u_umin >= umax_roi) && (v_vmin >= vmin_roi) && (u_umax >= umax_roi) && (v_vmax >= vmin_roi)) {
358  // The circle crosses the u-axis outside the roi
359  // so it is equivalent to the case of crossing only the right border
360  //Case crossing right only
361  computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta);
362  }
363  else if ((u_umin <= umax_roi) && (v_vmin <= vmin_roi) && (u_umax <= umax_roi) && (v_vmax <= vmin_roi)) {
364  // The circle crosses the v-axis outside the roi
365  // so it is equivalent to the case of crossing only the top border
366  //Case crossing top only
367  computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta);
368  }
369 }
370 
382 void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmax_roi, const float &radius,
383  float &delta_theta)
384 {
385  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
386  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
387  float crossing_u = vmax_roi; // We cross the u-axis of the RoI at which v-coordinate
388  float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate
389  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v,
390  crossing_theta_u_min, crossing_theta_u_max,
391  crossing_theta_v_min, crossing_theta_v_max);
392  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
393  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
394  float u_umin = crossing_theta_u_min.second;
395  float u_umax = crossing_theta_u_max.second;
396  float v_vmin = crossing_theta_v_min.second;
397  float v_vmax = crossing_theta_v_max.second;
398  if ((u_umin < umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmax_roi) && (v_vmax > vmax_roi)) {
399  // The circle crosses only once each axis
400  //Case crossing once
401  delta_theta = theta_v_min - theta_u_max;
402  }
403  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
404  // The circle crosses twice each axis
405  //Case crossing twice
406  delta_theta = (theta_v_min - theta_u_max) + (theta_u_min - theta_v_max);
407  }
408  else if ((u_umin < umin_roi) && (u_umax < umin_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
409  // The circle crosses the u-axis outside the roi
410  // so it is equivalent to the case of crossing only the left border
411  //Case left only
412  computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta);
413  }
414  else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin >= vmax_roi) && (v_vmax >= vmax_roi)) {
415  // The circle crosses the v-axis outside the roi
416  // so it is equivalent to the case of crossing only the bottom border
417  //Case bottom only
418  computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta);
419  }
420 }
421 
433 void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const float &vmax_roi, const float &umax_roi, const float &radius,
434  float &delta_theta)
435 {
436  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
437  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
438  float crossing_u = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
439  float crossing_v = umax_roi; // We cross the v-axis of the RoI at the maximum u-coordinate of the RoI
440  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v,
441  crossing_theta_u_min, crossing_theta_u_max,
442  crossing_theta_v_min, crossing_theta_v_max);
443  float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
444  float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
445  float u_umin = crossing_theta_u_min.second;
446  float u_umax = crossing_theta_u_max.second;
447  float v_vmin = crossing_theta_v_min.second;
448  float v_vmax = crossing_theta_v_max.second;
449  if ((u_umin <= umax_roi) && (u_umax > umax_roi) && (v_vmin <= vmax_roi) && (v_vmax > vmax_roi)) {
450  // The circle crosses only once each axis
451  //Case crossing once
452  delta_theta = theta_u_min - theta_v_min;
453  if (delta_theta < 0) {
454  // An arc length cannot be negative it means that theta_u_max was comprise in the bottom left quadrant of the circle
455  delta_theta += 2.f * M_PIf;
456  }
457  }
458  else if ((u_umin <= umax_roi) && (u_umax <= umax_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
459  // The circle crosses twice each axis
460  //Case crossing twice
461  delta_theta = (2.f * M_PIf) - ((theta_v_min - theta_v_max) + (theta_u_max - theta_u_min));
462  }
463  else if ((u_umin > umax_roi) && (u_umax > umax_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
464  // The circle crosses the u-axis outside the roi
465  // so it is equivalent to the case of crossing only the right border
466  //Case left only
467  computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta);
468  }
469  else if ((u_umin <= umax_roi) && (u_umax <= umax_roi) && (v_vmin > vmax_roi) && (v_vmax > vmax_roi)) {
470  // The circle crosses the v-axis outside the roi
471  // so it is equivalent to the case of crossing only the bottom border
472  //Case bottom only
473  computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta);
474  }
475 }
476 
489 void computeIntersectionsTopLeftBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi,
490  const float &vmax_roi, const float &radius, float &delta_theta)
491 {
492  // Computing the intersections with the top and left axes
493  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
494  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
495  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
496  float crossing_v = umin_roi; // We cross the v-axis of the RoI at the minimum u-coordinate of the RoI
497  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v,
498  crossing_theta_u_min, crossing_theta_u_max,
499  crossing_theta_v_min, crossing_theta_v_max);
500  float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
501  float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
502  float u_umin_top = crossing_theta_u_min.second;
503  float u_umax_top = crossing_theta_u_max.second;
504  float v_vmin = crossing_theta_v_min.second;
505  float v_vmax = crossing_theta_v_max.second;
506 
507  // Computing the intersections with the bottom and left axes
508  float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
509  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v,
510  crossing_theta_u_min, crossing_theta_u_max,
511  crossing_theta_v_min, crossing_theta_v_max);
512  float theta_u_min_bottom = crossing_theta_u_min.first;
513  float theta_u_max_bottom = crossing_theta_u_max.first;
514  float u_umin_bottom = crossing_theta_u_min.second;
515  float u_umax_bottom = crossing_theta_u_max.second;
516  if ((u_umin_top >= umin_roi) && (u_umin_bottom >= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
517  // case intersection top + left + bottom twice
518  delta_theta = (theta_v_min - theta_u_min_top) + (theta_u_max_top - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max);
519  }
520  else if ((u_umin_top <= umin_roi) && (v_vmin <= vmin_roi) && (u_umin_bottom <= umin_roi) && (v_vmax >= vmax_roi)) {
521  // case intersection top and bottom
522  delta_theta = (theta_u_max_top - theta_u_max_bottom);
523  }
524  else if ((u_umax_top <= umin_roi) && (u_umax_bottom <= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
525  // case left only
526  computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta);
527  }
528  else if ((u_umax_bottom > umin_roi) && (v_vmin >= vmin_roi)) {
529  // case bottom/left corner
530  computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
531  }
532  else if ((u_umax_top > umin_roi) && (v_vmax <= vmax_roi)) {
533  // case top/left corner
534  computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
535  }
536 }
537 
550 void computeIntersectionsTopRightBottom(const float &u_c, const float &v_c, const float &umax_roi, const float &vmin_roi, const float &vmax_roi,
551  const float &radius, float &delta_theta)
552 {
553  // Computing the intersections with the top and right axes
554  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
555  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
556  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
557  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
558  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v,
559  crossing_theta_u_min, crossing_theta_u_max,
560  crossing_theta_v_min, crossing_theta_v_max);
561  float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
562  float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
563  float u_umin_top = crossing_theta_u_min.second;
564  float u_umax_top = crossing_theta_u_max.second;
565  float v_vmin = crossing_theta_v_min.second;
566  float v_vmax = crossing_theta_v_max.second;
567 
568  // Computing the intersections with the bottom and right axes
569  float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
570  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v,
571  crossing_theta_u_min, crossing_theta_u_max,
572  crossing_theta_v_min, crossing_theta_v_max);
573  float theta_u_min_bottom = crossing_theta_u_min.first;
574  float theta_u_max_bottom = crossing_theta_u_max.first;
575  float u_umin_bottom = crossing_theta_u_min.second;
576  float u_umax_bottom = crossing_theta_u_max.second;
577  if ((u_umax_top <= umax_roi) && (u_umax_bottom <= umax_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
578  // case intersection top + right + bottom twice
579  delta_theta = (2.f * M_PIf) - ((theta_u_min_top - theta_u_max_top) + (theta_v_min - theta_v_max) + (theta_u_max_bottom - theta_u_min_bottom));
580  }
581  else if ((u_umin_top <= umax_roi) && (u_umax_top > umax_roi) && (v_vmin <= vmin_roi) && (u_umin_bottom <= umax_roi) && (u_umax_bottom > umax_roi) && (v_vmax >= vmax_roi)) {
582  // case intersection top and bottom
583  delta_theta = (theta_u_max_top - theta_u_max_bottom);
584  }
585  else if ((u_umin_top >= umax_roi) && (u_umin_bottom >= umax_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
586  // case right only
587  computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta);
588  }
589  else if ((u_umin_bottom <= umax_roi) && (v_vmin >= vmin_roi)) {
590  // case bottom/right corner
591  computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
592  }
593  else if ((u_umin_top <= umax_roi) && (v_vmax <= vmax_roi)) {
594  // case top/right corner
595  computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
596  }
597 }
598 
610 void computeIntersectionsTopBottomOnly(const float &u_c, const float &v_c, const float &vmin_roi, const float &vmax_roi, const float &radius,
611  float &delta_theta)
612 {
613  // Computing the two angles for which the u-axis is crossed at the top of the RoI
614  // v = vc - r sin(theta) because the v-axis goes down
615  // theta = asin((vc - vmin_roi)/r)
616  float theta_u_cross_top = std::asin((v_c - vmin_roi) / radius);
617  theta_u_cross_top = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross_top);
618  float theta_u_cross_top_2 = 0.f;
619  if (theta_u_cross_top > 0) {
620  theta_u_cross_top_2 = M_PIf - theta_u_cross_top;
621  }
622  else {
623  theta_u_cross_top_2 = -M_PIf - theta_u_cross_top;
624  }
625 
626  // Computing the corresponding u-coordinates at which the u-axis is crossed
627  float u_ucross_top = u_c + (radius * std::cos(theta_u_cross_top));
628  float u_ucross_top_2 = u_c + (radius * std::cos(theta_u_cross_top_2));
629  // Sorting the outputs such as u(theta_u_cross_top_min) < u(theta_u_cross_top_max)
630  float theta_u_cross_top_min = 0.f, theta_u_cross_top_max = 0.f;
631  if (u_ucross_top < u_ucross_top_2) {
632  theta_u_cross_top_min = theta_u_cross_top;
633  theta_u_cross_top_max = theta_u_cross_top_2;
634  }
635  else {
636  theta_u_cross_top_min = theta_u_cross_top_2;
637  theta_u_cross_top_max = theta_u_cross_top;
638  }
639 
640  // Computing the two angles for which the u-axis is crossed at the bottom of the RoI
641  // v = vc - r sin(theta) because the v-axis goes down
642  // theta = asin((vc - vmax_roi)/r)
643  float theta_u_cross_bottom = std::asin((v_c - vmax_roi) / radius);
644  theta_u_cross_bottom = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross_bottom);
645  float theta_u_cross_bottom_2 = 0.f;
646  if (theta_u_cross_bottom > 0) {
647  theta_u_cross_bottom_2 = M_PIf - theta_u_cross_bottom;
648  }
649  else {
650  theta_u_cross_bottom_2 = -M_PIf - theta_u_cross_bottom;
651  }
652 
653  // Computing the corresponding u-coordinates at which the u-axis is crossed
654  float u_ucross_bottom = u_c + (radius * std::cos(theta_u_cross_bottom));
655  float u_ucross_bottom_2 = u_c + (radius * std::cos(theta_u_cross_bottom_2));
656 
657  // Sorting the outputs such as u(theta_u_cross_bottom_min) < u(theta_u_cross_bottom_max)
658  float theta_u_cross_bottom_min = 0.f, theta_u_cross_bottom_max = 0.f;
659  if (u_ucross_bottom < u_ucross_bottom_2) {
660  theta_u_cross_bottom_min = theta_u_cross_bottom;
661  theta_u_cross_bottom_max = theta_u_cross_bottom_2;
662  }
663  else {
664  theta_u_cross_bottom_min = theta_u_cross_bottom_2;
665  theta_u_cross_bottom_max = theta_u_cross_bottom;
666  }
667 
668  // Computing the the length of the angular interval of the circle when it intersects
669  // only with the top and bottom borders of the Region of Interest (RoI)
670  delta_theta = (2.f * M_PIf) - ((theta_u_cross_top_min - theta_u_cross_top_max) + (theta_u_cross_bottom_max - theta_u_cross_bottom_min));
671 }
672 
685 void computeIntersectionsLeftRightTop(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
686  const float &vmin_roi, const float &radius, float &delta_theta)
687 {
688  // Computing the intersections with the top and left axes
689  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
690  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
691  float crossing_u = vmin_roi; // We cross the u-axis of the RoI at the minimum v-coordinate of the RoI
692  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
693  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_left,
694  crossing_theta_u_min, crossing_theta_u_max,
695  crossing_theta_v_min, crossing_theta_v_max);
696  float theta_u_min = crossing_theta_u_min.first;
697  float theta_u_max = crossing_theta_u_max.first;
698  float u_umin = crossing_theta_u_min.second;
699  float u_umax = crossing_theta_u_max.second;
700  float theta_v_min_left = crossing_theta_v_min.first;
701  float theta_v_max_left = crossing_theta_v_max.first;
702  float v_vmin_left = crossing_theta_v_min.second;
703  float v_vmax_left = crossing_theta_v_max.second;
704 
705  // Computing the intersections with the rigt and top axes
706  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
707  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_right,
708  crossing_theta_u_min, crossing_theta_u_max,
709  crossing_theta_v_min, crossing_theta_v_max);
710  float theta_v_min_right = crossing_theta_v_min.first;
711  float theta_v_max_right = crossing_theta_v_max.first;
712  float v_vmin_right = crossing_theta_v_min.second;
713  float v_vmax_right = crossing_theta_v_max.second;
714 
715  if ((u_umin >= umin_roi) && (u_umax <= umax_roi) && (v_vmin_left >= vmin_roi) && (v_vmin_right >= vmin_roi)) {
716  // case intersection left + right + top twice
717  delta_theta = (theta_v_min_left - theta_u_min) + (theta_u_max - theta_v_min_right) + (theta_v_max_right - theta_v_max_left);
718  }
719  else if ((u_umin <= umin_roi) && (u_umax >= umax_roi) && (v_vmax_left >= vmin_roi) && (v_vmax_right >= vmin_roi)) {
720  // case intersection left + right
721  delta_theta = (theta_v_max_right - theta_v_max_left);
722  }
723  else if ((v_vmax_left <= vmin_roi) && (v_vmax_right <= vmin_roi) && (u_umin >= umin_roi) && (u_umax <= umax_roi)) {
724  // case top only
725  computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta);
726  }
727  else if ((u_umax >= umin_roi) && (v_vmax_left >= vmin_roi)) {
728  // case top/left corner
729  computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
730  }
731  else if ((u_umin <= umax_roi) && (v_vmax_right >= vmin_roi)) {
732  // case top/right corner
733  computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
734  }
735 }
736 
749 void computeIntersectionsLeftRightBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
750  const float &vmax_roi, const float &radius, float &delta_theta)
751 {
752  // Computing the intersections with the bottom and left axes
753  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
754  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
755  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
756  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
757  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_left,
758  crossing_theta_u_min, crossing_theta_u_max,
759  crossing_theta_v_min, crossing_theta_v_max);
760  float theta_u_min = crossing_theta_u_min.first;
761  float theta_u_max = crossing_theta_u_max.first;
762  float u_umin = crossing_theta_u_min.second;
763  float u_umax = crossing_theta_u_max.second;
764  float theta_v_min_left = crossing_theta_v_min.first;
765  float theta_v_max_left = crossing_theta_v_max.first;
766  float v_vmin_left = crossing_theta_v_min.second;
767  // --comment: float v_vmax_left equals crossing_theta_v_max dot second
768 
769  // Computing the intersections with the bottom and right axes
770  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
771  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u, crossing_v_right,
772  crossing_theta_u_min, crossing_theta_u_max,
773  crossing_theta_v_min, crossing_theta_v_max);
774  float theta_v_min_right = crossing_theta_v_min.first;
775  float theta_v_max_right = crossing_theta_v_max.first;
776  float v_vmin_right = crossing_theta_v_min.second;
777  // --comment: float v_vmax_right equals crossing_theta_v_max dot second
778 
779  if ((u_umin >= umin_roi) && (u_umax <= umax_roi) && (v_vmin_left <= vmax_roi) && (v_vmin_right <= vmax_roi)) {
780  // case intersection left + right + bottom twice
781  delta_theta = (theta_v_min_left - theta_v_min_right) + (theta_v_max_right - theta_u_max) + (theta_u_min - theta_v_max_left);
782  }
783  else if ((u_umin <= umin_roi) && (u_umax >= umax_roi) && (v_vmin_left <= vmax_roi) && (v_vmin_right <= vmax_roi)) {
784  // case intersection left + right
785  delta_theta = (theta_v_min_left - theta_v_min_right);
786  }
787  else if ((v_vmin_left >= vmax_roi) && (v_vmin_right >= vmax_roi) && (u_umin >= umin_roi) && (u_umax <= umax_roi)) {
788  // case bottom only
789  computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta);
790  }
791  else if ((u_umax >= umin_roi) && (v_vmin_right >= vmax_roi)) {
792  // case bottom/left corner
793  computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
794  }
795  else if ((u_umin <= umax_roi) && (v_vmin_right <= vmax_roi)) {
796  // case bottom/right corner
797  computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
798  }
799 }
800 
812 void computeIntersectionsLeftRightOnly(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi, const float &radius,
813  float &delta_theta)
814 {
815  // Computing the two angles for which the v-axis is crossed at the left of the RoI
816  // umin_roi = u_c + r cos(theta)
817  // theta = acos((umin_roi - u_c)/r)
818  // theta_min = -theta_max
819  float theta_v_cross_left = std::acos((umin_roi - u_c) / radius);
820  theta_v_cross_left = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross_left);
821  float theta_v_cross_left_2 = -theta_v_cross_left;
822 
823  // Computing the corresponding v-coordinates at which the v-axis is crossed
824  float v_vcross_left = v_c - (radius * std::sin(theta_v_cross_left));
825  float v_vcross_left_2 = v_c - (radius * std::sin(theta_v_cross_left_2));
826  // Sorting the outputs such as v(theta_v_cross_left_min) < v(theta_v_cross_left_max)
827  float theta_v_cross_left_min = 0.f, theta_v_cross_left_max = 0.f;
828  if (v_vcross_left < v_vcross_left_2) {
829  theta_v_cross_left_min = theta_v_cross_left;
830  theta_v_cross_left_max = theta_v_cross_left_2;
831  }
832  else {
833  theta_v_cross_left_min = theta_v_cross_left_2;
834  theta_v_cross_left_max = theta_v_cross_left;
835  }
836 
837  // Computing the two angles for which the v-axis is crossed at the right of the RoI
838  // umax_roi = u_c + r cos(theta)
839  // theta = acos((umin_roi - u_c)/r)
840  // theta_min = -theta_max
841  float theta_v_cross_right = std::acos((umax_roi - u_c) / radius);
842  theta_v_cross_right = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross_right);
843  float theta_v_cross_right_2 = -theta_v_cross_right;
844 
845  // Computing the corresponding v-coordinates at which the v-axis is crossed
846  float v_vcross_right = v_c - (radius * std::sin(theta_v_cross_right));
847  float v_vcross_right_2 = v_c - (radius * std::sin(theta_v_cross_right_2));
848 
849  // Sorting the outputs such as v(theta_v_cross_right_min) < v(theta_v_cross_right_max)
850  float theta_v_cross_right_min = 0.f, theta_v_cross_right_max = 0.f;
851  if (v_vcross_right < v_vcross_right_2) {
852  theta_v_cross_right_min = theta_v_cross_right;
853  theta_v_cross_right_max = theta_v_cross_right_2;
854  }
855  else {
856  theta_v_cross_right_min = theta_v_cross_right_2;
857  theta_v_cross_right_max = theta_v_cross_right;
858  }
859 
860  // Computing the the length of the angular interval of the circle when it intersects
861  // only with the top and bottom borders of the Region of Interest (RoI)
862  delta_theta = (theta_v_cross_left_min - theta_v_cross_right_min) + (theta_v_cross_right_max - theta_v_cross_left_max);
863 }
864 
865 
879 void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
880  const float &vmin_roi, const float &vmax_roi, const float &radius, float &delta_theta)
881 {
882  // Computing the intersections with the top and left axes
883  std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
884  std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
885  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
886  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
887  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_top, crossing_v_left,
888  crossing_theta_u_min, crossing_theta_u_max,
889  crossing_theta_v_min, crossing_theta_v_max);
890  float theta_u_min_top = crossing_theta_u_min.first;
891  float theta_u_max_top = crossing_theta_u_max.first;
892  float theta_v_min_left = crossing_theta_v_min.first;
893  float theta_v_max_left = crossing_theta_v_max.first;
894 
895  // Computing the intersections with the bottom and right axes
896  float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
897  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
898  computePerpendicularAxesIntersections(u_c, v_c, radius, crossing_u_bottom, crossing_v_right,
899  crossing_theta_u_min, crossing_theta_u_max,
900  crossing_theta_v_min, crossing_theta_v_max);
901  float theta_u_min_bottom = crossing_theta_u_min.first;
902  float theta_u_max_bottom = crossing_theta_u_max.first;
903  float theta_v_min_right = crossing_theta_v_min.first;
904  float theta_v_max_right = crossing_theta_v_max.first;
905  delta_theta = (theta_v_min_left - theta_u_min_top) + (theta_u_max_top - theta_v_min_right);
906  delta_theta += (theta_v_max_right - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max_left);
907 }
908 
909 float vpImageCircle::computeAngularCoverageInRoI(const vpRect &roi, const float &roundingTolerance) const
910 {
911  float delta_theta = 0.f;
912  vpImagePoint center = m_center;
913  float u_c = static_cast<float>(center.get_u());
914  float v_c = static_cast<float>(center.get_v());
915  float radius = m_radius;
916  float roi_w = static_cast<float>(roi.getWidth());
917  float roi_h = static_cast<float>(roi.getHeight());
918  vpImagePoint topLeft = roi.getTopLeft();
919  float umin_roi = static_cast<float>(topLeft.get_u());
920  float vmin_roi = static_cast<float>(topLeft.get_v());
921  float umax_roi = umin_roi + roi_w;
922  float vmax_roi = vmin_roi + roi_h;
923  bool touchLeftBorder = (u_c - radius) <= umin_roi;
924  bool touchRightBorder = (u_c + radius) >= umax_roi;
925  bool touchTopBorder = (v_c - radius) <= vmin_roi;
926  bool touchBottomBorder = (v_c + radius) >= vmax_roi;
927  bool isHorizontallyOK = ((!touchLeftBorder) && (!touchRightBorder));
928  bool isVerticallyOK = ((!touchTopBorder) && (!touchBottomBorder));
929  if (isHorizontallyOK && isVerticallyOK && roi.isInside(m_center)) {
930  // Easy case
931  // The circle has its center in the image and its radius is not too great
932  // to make it fully contained in the RoI
933  delta_theta = 2.f * M_PIf;
934  }
935  else if (touchBottomBorder && (!touchLeftBorder) && (!touchRightBorder) && (!touchTopBorder)) {
936  // Touches/intersects only the bottom border of the RoI
937  computeIntersectionsBottomBorderOnly(v_c, vmax_roi, radius, delta_theta);
938  }
939  else if ((!touchBottomBorder) && touchLeftBorder && (!touchRightBorder) && (!touchTopBorder)) {
940  // Touches/intersects only the left border of the RoI
941  computeIntersectionsLeftBorderOnly(u_c, umin_roi, radius, delta_theta);
942  }
943  else if ((!touchBottomBorder) && (!touchLeftBorder) && touchRightBorder && (!touchTopBorder)) {
944  // Touches/intersects only the right border of the RoI
945  computeIntersectionsRightBorderOnly(u_c, umax_roi, radius, delta_theta);
946  }
947  else if ((!touchBottomBorder) && (!touchLeftBorder) && (!touchRightBorder) && touchTopBorder) {
948  // Touches/intersects only the top border of the RoI
949  computeIntersectionsTopBorderOnly(v_c, vmin_roi, radius, delta_theta);
950  }
951  else if (touchBottomBorder && touchLeftBorder && (!touchRightBorder) && (!touchTopBorder)) {
952  // Touches/intersects the bottom and left borders of the RoI
953  computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
954  }
955  else if (touchBottomBorder && (!touchLeftBorder) && touchRightBorder && (!touchTopBorder)) {
956  // Touches/intersects the bottom and right borders of the RoI
957  computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
958  }
959  else if ((!touchBottomBorder) && touchLeftBorder && (!touchRightBorder) && touchTopBorder) {
960  // Touches/intersects the top and left borders of the RoI
961  computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
962  }
963  else if ((!touchBottomBorder) && (!touchLeftBorder) && touchRightBorder && touchTopBorder) {
964  // Touches/intersects the top and right borders of the RoI
965  computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
966  }
967  else if (touchBottomBorder && touchTopBorder && touchLeftBorder && (!touchRightBorder)) {
968  // Touches/intersects the top, left and bottom borders of the RoI
969  computeIntersectionsTopLeftBottom(u_c, v_c, umin_roi, vmin_roi, vmax_roi, radius, delta_theta);
970  }
971  else if (touchBottomBorder && touchTopBorder && (!touchLeftBorder) && touchRightBorder) {
972  // Touches/intersects the top, right and bottom borders of the RoI
973  computeIntersectionsTopRightBottom(u_c, v_c, umax_roi, vmin_roi, vmax_roi, radius, delta_theta);
974  }
975  else if (touchBottomBorder && touchTopBorder && (!touchLeftBorder) && (!touchRightBorder)) {
976  // Touches/intersects the top and bottom borders of the RoI
977  computeIntersectionsTopBottomOnly(u_c, v_c, vmin_roi, vmax_roi, radius, delta_theta);
978  }
979  else if ((!touchBottomBorder) && touchTopBorder && touchLeftBorder && touchRightBorder) {
980  // Touches/intersects the top, left and right borders of the RoI
981  computeIntersectionsLeftRightTop(u_c, v_c, umin_roi, umax_roi, vmin_roi, radius, delta_theta);
982  }
983  else if (touchBottomBorder && (!touchTopBorder) && touchLeftBorder && touchRightBorder) {
984  // Touches/intersects the bottom, left and right borders of the RoI
985  computeIntersectionsLeftRightBottom(u_c, v_c, umin_roi, umax_roi, vmax_roi, radius, delta_theta);
986  }
987  else if (touchLeftBorder && touchRightBorder && (!touchTopBorder) && (!touchBottomBorder)) {
988  // Touches/intersects the bottom, left and right borders of the RoI
989  computeIntersectionsLeftRightOnly(u_c, v_c, umin_roi, umax_roi, radius, delta_theta);
990  }
991  else if (touchLeftBorder && touchRightBorder && touchTopBorder && touchBottomBorder) {
992  // Touches/intersects each axis
993  computeIntersectionsAllAxes(u_c, v_c, umin_roi, umax_roi, vmin_roi, vmax_roi, radius, delta_theta);
994  }
995  else {
996  std::cerr << "touchLeft = " << (touchLeftBorder ? "true" : "false") << "\ttouchRight = " << (touchRightBorder ? "true" : "false") << std::endl;
997  std::cerr << "touchTop = " << (touchTopBorder ? "true" : "false") << "\ttouchBottom = " << (touchBottomBorder ? "true" : "false") << std::endl;
998  std::cerr << "u_c = " << u_c << "\tv_c = " << v_c << "\tradius = " << radius << std::endl;
999  std::cerr << "umin_roi = " << umin_roi << "\tumax_roi = " << umax_roi << std::endl;
1000  std::cerr << "vmin_roi = " << vmin_roi << "\tvmax_roi = " << vmax_roi << std::endl << std::flush;
1001  throw(vpException(vpException::fatalError, "This case should never happen. Please contact Inria to make fix the problem"));
1002  }
1003 
1004  if ((delta_theta < 0) || (delta_theta >(2.f * M_PIf))) { // Needed since M_PIf is used
1005  float rest = vpMath::modulo(delta_theta, 2.f * M_PIf);
1006  if ((rest < roundingTolerance) && ((delta_theta < -M_PIf) || (delta_theta > M_PIf))) {
1007  // If the angle is a negative multiple of 2.f * M_PIf we consider it to be 2.f * M_PIf
1008  delta_theta = 2.f * M_PIf;
1009  }
1010  else {
1011  //Otherwise, it corresponds to delta_theta modulo 2.f * M_PIf
1012  delta_theta = rest;
1013  }
1014  }
1015 
1016  return delta_theta;
1017 }
1018 
1019 float vpImageCircle::computeArcLengthInRoI(const vpRect &roi, const float &roundingTolerance) const
1020 {
1021  float delta_theta = computeAngularCoverageInRoI(roi, roundingTolerance);
1022  return delta_theta * m_radius;
1023 }
1024 
1025 #if (VISP_CXX_STANDARD == VISP_CXX_STANDARD_98)
1026 namespace
1027 {
1028 // Increment the counter if the considered pixel (x, y) is in the mask image
1029 void incrementIfIsInMask(const vpImage<bool> &mask, const int &width, const int &height, const int &x, const int &y,
1030  unsigned int &count)
1031 {
1032  if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1033  // The pixel is outside the limit of the mask
1034  return;
1035  }
1036  if (mask[y][x]) {
1037  // Increment only if the pixel value of the mask is true
1038  count++;
1039  }
1040 }
1041 };
1042 #endif
1043 
1044 unsigned int vpImageCircle::computePixelsInMask(const vpImage<bool> &mask) const
1045 {
1046  const float xm = static_cast<float>(m_center.get_u()), ym = static_cast<float>(m_center.get_v());
1047  const float r_float = static_cast<float>(m_radius);
1048  const int width = mask.getWidth();
1049  const int height = mask.getHeight();
1050 
1051 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
1052  // Increment the counter if the considered pixel (x, y) is in the mask image
1053  auto incrementIfIsInMask = [](const vpImage<bool> &mask, const int &width, const int &height, const int &x, const int &y,
1054  unsigned int &count) {
1055  if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1056  // The pixel is outside the limit of the mask
1057  return;
1058  }
1059  if (mask[y][x]) {
1060  // Increment only if the pixel value of the mask is true
1061  count++;
1062  }
1063  };
1064 #endif
1065  unsigned int count = 0; // Count the number of pixels of the circle whose value in the mask is true
1066 
1067  const float thetaStop = M_PI_2f;
1068  float theta = 0;
1069  int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
1070  int y1 = 0, y2 = 0, y3 = 0, y4 = 0;
1071  while (theta < thetaStop) {
1072  float cos_theta = std::cos(theta);
1073  float sin_theta = std::sin(theta);
1074  float rcos_pos = r_float * cos_theta;
1075  float rsin_pos = r_float * sin_theta;
1076  x1 = static_cast<int>(xm + rcos_pos); // theta
1077  y1 = static_cast<int>(ym + rsin_pos); // theta
1078  x2 = static_cast<int>(xm - rsin_pos); // theta + pi
1079  y2 = static_cast<int>(ym + rcos_pos); // theta + pi
1080  x3 = static_cast<int>(xm - rcos_pos); // theta + pi/2
1081  y3 = static_cast<int>(ym - rsin_pos); // theta + pi/2
1082  x4 = static_cast<int>(xm + rsin_pos); // theta + pi
1083  y4 = static_cast<int>(ym - rcos_pos); // theta + pi
1084  incrementIfIsInMask(mask, width, height, x1, y1, count);
1085  incrementIfIsInMask(mask, width, height, x2, y2, count);
1086  incrementIfIsInMask(mask, width, height, x3, y3, count);
1087  incrementIfIsInMask(mask, width, height, x4, y4, count);
1088 
1089  // Looking for dtheta such as either x or 1 increments of 1 pix exactly
1090  // Using series expansion, we get that if we want to have an increment of
1091  // 1 pixel for the derivative along x (resp. y), we have to respect the
1092  // following formulae
1093  float dthetaCosPos = 1.f / (r_float * cos_theta);
1094  float dthetaCosNeg = -1.f / (r_float * cos_theta);
1095  float dthetaSinPos = 1.f / (r_float * sin_theta);
1096  float dthetaSinNeg = -1.f / (r_float * sin_theta);
1097  float dthetaPos = 0.f;
1098  if ((sin_theta < 0.f) && (cos_theta > 0.f)) {
1099  // --comment: dTheta lesseq -1/r sin(theta) and dTheta lesseq 1/r cos(theta)
1100  dthetaPos = std::min<float>(dthetaCosPos, dthetaSinNeg);
1101  }
1102  else if ((sin_theta > 0.f) && (cos_theta < 0.f)) {
1103  // --comment: dTheta lesseq 1/r sin(theta) and dTheta lesseq -1/r cos(theta)
1104  dthetaPos = std::min<float>(dthetaCosNeg, dthetaSinPos);
1105  }
1106  else if ((sin_theta < 0.f) && (cos_theta < 0.f)) {
1107  // --comment: dTheta lesseq -1/r sin(theta) and dTheta lesseq -1/r cos(theta)
1108  dthetaPos = std::min<float>(dthetaCosNeg, dthetaSinNeg);
1109  }
1110  else if ((sin_theta > 0.f) && (cos_theta > 0.f)) {
1111  // --comment: dTheta lesseq 1/r sin(theta) and dTheta lesseq 1/r cos(theta)
1112  dthetaPos = std::min<float>(dthetaCosPos, dthetaSinPos);
1113  }
1114  else if (vpMath::equal(sin_theta, 0.f) && (!vpMath::equal(cos_theta, 0.f))) {
1115  // --comment: dTheta eq -1 / r cos(theta) or dTheta eq 1 / r cos(theta)
1116  if (cos_theta > 0.f) {
1117  dthetaPos = dthetaCosNeg;
1118  }
1119  else {
1120  dthetaPos = dthetaCosPos;
1121  }
1122  }
1123  else if ((!vpMath::equal(sin_theta, 0.f)) && vpMath::equal(cos_theta, 0.f)) {
1124  // --comment: dTheta eq -1 / r sin(theta) or dTheta eq 1 / r sin(theta)
1125  if (sin_theta > 0.f) {
1126  dthetaPos = dthetaSinNeg;
1127  }
1128  else {
1129  dthetaPos = dthetaSinPos;
1130  }
1131  }
1132  theta += dthetaPos;
1133  }
1134  return count;
1135 }
1136 
1138 {
1139  return m_center;
1140 }
1141 
1143 {
1144  return m_radius;
1145 }
1146 
1148 {
1149  vpRect bbox(m_center - vpImagePoint(m_radius, m_radius), 2 * m_radius, 2 * m_radius);
1150  return bbox;
1151 }
1152 
1154 {
1155  return (m_radius * m_radius) / 4;
1156 }
1157 
1159 {
1160  return (m_radius * m_radius) / 4;
1161 }
1162 
1164 {
1165  return 0.;
1166 };
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ fatalError
Fatal error.
Definition: vpException.h:84
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:245
unsigned int getHeight() const
Definition: vpImage.h:184
static float getAngleBetweenMinPiAndPi(const float &theta)
Definition: vpMath.h:137
static bool equal(double x, double y, double threshold=0.001)
Definition: vpMath.h:449
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:175
Defines a rectangle in the plane.
Definition: vpRect.h:76
double getWidth() const
Definition: vpRect.h:224
bool isInside(const vpImagePoint &ip) const
Definition: vpRect.cpp:121
vpImagePoint getTopLeft() const
Definition: vpRect.h:196
double getHeight() const
Definition: vpRect.h:163