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