Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpImageCircle.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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
39void computeIntersectionsLeftBorder(const float &u_c, const float &umin_roi, const float &radius, float &delta_theta);
40void computeIntersectionsRightBorder(const float &u_c, const float &umax_roi, const float &radius, float &delta_theta);
41void computeIntersectionsTopBorder(const float &v_c, const float &vmin_roi, const float &radius, float &delta_theta);
42void computeIntersBottomBorder(const float &v_c, const float &vmax_roi, const float &radius, float &delta_theta);
43void computePerpendicularAxesInters(const float &u_c, const float &v_c, const float &radius,
44 const float &crossing_u, const float &crossing_v,
45 std::pair<float, float> &theta_u_cross_min, std::pair<float, float> &theta_u_cross_max,
46 std::pair<float, float> &theta_v_cross_min, std::pair<float, float> &theta_v_cross_max);
47void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi,
48 const float &radius, float &delta_theta);
49void computeIntersectionsTopRight(const float &u_c, const float &v_c, const float &vmin_roi, const float &umax_roi,
50 const float &radius, float &delta_theta);
51void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmax_roi,
52 const float &radius, float &delta_theta);
53void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const float &vmax_roi, const float &umax_roi,
54 const float &radius, float &delta_theta);
55void computeIntersTopLeftBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi,
56 const float &vmax_roi, const float &radius, float &delta_theta);
57void computeIntersTopRightBottom(const float &u_c, const float &v_c, const float &umax_roi, const float &vmin_roi,
58 const float &vmax_roi, const float &radius, float &delta_theta);
59void computeIntersTopBottomOnly(const float &u_c, const float &v_c, const float &vmin_roi, const float &vmax_roi,
60 const float &radius, float &delta_theta);
61void computeIntersLeftRightTop(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
62 const float &vmin_roi, const float &radius, float &delta_theta);
63void computeIntersLeftRightBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
64 const float &vmax_roi, const float &radius, float &delta_theta);
65void computeIntersectionsLeftRight(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
66 const float &radius, float &delta_theta);
67void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
68 const float &vmin_roi, const float &vmax_roi, const float &radius, float &delta_theta);
69
71 : m_center()
72 , m_radius(0.)
73{
74
75}
76
77vpImageCircle::vpImageCircle(const vpImagePoint &center, const float &radius)
78 : m_center(center)
79 , m_radius(radius)
80{
81
82}
83
84#ifdef HAVE_OPENCV_CORE
85vpImageCircle::vpImageCircle(const cv::Vec3f &vec)
86{
87 const unsigned int index_0 = 0;
88 const unsigned int index_1 = 1;
89 const unsigned int index_2 = 2;
90 m_center = vpImagePoint(static_cast<double>(vec[index_1]), static_cast<double>(vec[index_0]));
91 m_radius = vec[index_2];
92}
93#endif
94
104void computeIntersectionsLeftBorder(const float &u_c, const float &umin_roi, const float &radius, float &delta_theta)
105{
106 // --comment: umin_roi = u_c + r cos(theta)
107 // --comment: theta = acos of of umin_roi - u_c endof / r endof
108 const int val_2 = 2;
109 float theta1 = std::acos((umin_roi - u_c) / radius);
110 theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
111 float theta2 = -1.f * theta1;
112 float theta_min = std::min<float>(theta1, theta2);
113 float theta_max = std::max<float>(theta1, theta2);
114 delta_theta = theta_max - theta_min;
115 if ((u_c < umin_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
116 delta_theta = 0.f;
117 }
118}
119
129void computeIntersectionsRightBorder(const float &u_c, const float &umax_roi, const float &radius, float &delta_theta)
130{
131 // --comment: u = u_c + r cos(theta)
132 // --comment: theta = acos of of u - u_c endof / r endof
133 const int val_2 = 2;
134 float theta1 = std::acos((umax_roi - u_c) / radius);
135 theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
136 float theta2 = -1.f * theta1;
137 float theta_min = std::min<float>(theta1, theta2);
138 float theta_max = std::max<float>(theta1, theta2);
139 delta_theta = (2.f * M_PI_FLOAT) - (theta_max - theta_min);
140 if ((u_c > umax_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
141 delta_theta = 0.f;
142 }
143}
144
154void computeIntersectionsTopBorder(const float &v_c, const float &vmin_roi, const float &radius, float &delta_theta)
155{
156 // v = vc - r sin(theta) because the v-axis goes down
157 // theta = asin((vc - v)/r)
158 const int val_2 = 2;
159 float theta1 = std::asin((v_c - vmin_roi) / radius);
160 theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
161
162 float theta2 = 0.f;
163 if (theta1 >= 0.f) {
164 theta2 = M_PI_FLOAT - theta1;
165 }
166 else {
167 theta2 = -theta1 - M_PI_FLOAT;
168 }
169 float theta_min = std::min<float>(theta1, theta2);
170 float theta_max = std::max<float>(theta1, theta2);
171 if ((std::abs(theta_max - theta_min) * radius) < 1.f) {
172 // Between the maximum and minimum theta there is less than 1 pixel of difference
173 // It meens that the full circle is visible
174 delta_theta = 2.f * M_PI_FLOAT;
175 }
176 else if (theta1 > 0.f) {
177 delta_theta = (2.f * M_PI_FLOAT) - (theta_max - theta_min);
178 }
179 else {
180 delta_theta = theta_max - theta_min;
181 }
182 if ((v_c < vmin_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
183 delta_theta = 0.f;
184 }
185}
186
196void computeIntersBottomBorder(const float &v_c, const float &vmax_roi, const float &radius, float &delta_theta)
197{
198 // v = vc - r sin(theta) because the v-axis goes down
199 // theta = asin((vc - v)/r)
200 const int val_2 = 2;
201 float theta1 = std::asin((v_c - vmax_roi) / radius);
202 theta1 = vpMath::getAngleBetweenMinPiAndPi(theta1);
203
204 float theta2 = 0.f;
205 if (theta1 >= 0.f) {
206 theta2 = M_PI_FLOAT - theta1;
207 }
208 else {
209 theta2 = -theta1 - M_PI_FLOAT;
210 }
211 float theta_min = std::min<float>(theta1, theta2);
212 float theta_max = std::max<float>(theta1, theta2);
213 if ((std::abs(theta_max - theta_min) * radius) < 1.f) {
214 // Between the maximum and minimum theta there is less than 1 pixel of difference
215 // It meens that the full circle is visible
216 delta_theta = 2.f * M_PI_FLOAT;
217 }
218 else if (theta1 > 0.f) {
219 delta_theta = theta_max - theta_min;
220 }
221 else {
222 delta_theta = (2.f * M_PI_FLOAT) - (theta_max - theta_min);
223 }
224 if ((v_c > vmax_roi) && (std::abs(delta_theta - (val_2 * M_PI_FLOAT)) < (2.f * std::numeric_limits<float>::epsilon()))) {
225 delta_theta = 0.f;
226 }
227}
228
243void computePerpendicularAxesInters(const float &u_c, const float &v_c, const float &radius,
244 const float &crossing_u, const float &crossing_v,
245 std::pair<float, float> &theta_u_cross_min, std::pair<float, float> &theta_u_cross_max,
246 std::pair<float, float> &theta_v_cross_min, std::pair<float, float> &theta_v_cross_max)
247{
248 // Computing the two angles for which the u-axis is crossed
249 // v = vc - r sin(theta) because the v-axis goes down
250 // theta = asin((vc - v)/r)
251 float theta_u_cross = std::asin((v_c - crossing_u) / radius);
252 theta_u_cross = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross);
253 float theta_u_cross_2 = 0.f;
254 if (theta_u_cross > 0) {
255 theta_u_cross_2 = M_PI_FLOAT - theta_u_cross;
256 }
257 else {
258 theta_u_cross_2 = -M_PI_FLOAT - theta_u_cross;
259 }
260 // Computing the corresponding u-coordinates at which the u-axis is crossed
261 float u_ucross = u_c + (radius * std::cos(theta_u_cross));
262 float u_ucross2 = u_c + (radius * std::cos(theta_u_cross_2));
263 // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second
264 if (u_ucross < u_ucross2) {
265 theta_u_cross_min.first = theta_u_cross;
266 theta_u_cross_min.second = u_ucross;
267 theta_u_cross_max.first = theta_u_cross_2;
268 theta_u_cross_max.second = u_ucross2;
269 }
270 else {
271 theta_u_cross_min.first = theta_u_cross_2;
272 theta_u_cross_min.second = u_ucross2;
273 theta_u_cross_max.first = theta_u_cross;
274 theta_u_cross_max.second = u_ucross;
275 }
276
277 // Computing the two angles for which the v-axis is crossed
278 // u = u_c + r cos(theta)
279 // theta = acos((u - u_c) / r)
280 float theta_v_cross = std::acos((crossing_v - u_c) / radius);
281 theta_v_cross = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross);
282 float theta_v_cross_2 = -theta_v_cross;
283 // Computing the corresponding v-coordinates at which the v-axis is crossed
284 // v = v_c - radius sin(theta) because the v-axis is oriented towards the bottom
285 float v_vcross = v_c - (radius * std::sin(theta_v_cross));
286 float v_vcross2 = v_c - (radius * std::sin(theta_v_cross_2));
287 // Sorting the outputs such as theta_X_cross_min.second < theta_X_cross_max.second
288 if (v_vcross < v_vcross2) {
289 theta_v_cross_min.first = theta_v_cross;
290 theta_v_cross_min.second = v_vcross;
291 theta_v_cross_max.first = theta_v_cross_2;
292 theta_v_cross_max.second = v_vcross2;
293 }
294 else {
295 theta_v_cross_min.first = theta_v_cross_2;
296 theta_v_cross_min.second = v_vcross2;
297 theta_v_cross_max.first = theta_v_cross;
298 theta_v_cross_max.second = v_vcross;
299 }
300}
301
313void computeIntersectionsTopLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi,
314 const float &radius, float &delta_theta)
315{
316 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
317 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
318 float crossing_u = vmin_roi; // We cross the u-axis of the RoI at which v-coordinate
319 float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate
320 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v,
321 crossing_theta_u_min, crossing_theta_u_max,
322 crossing_theta_v_min, crossing_theta_v_max);
323 float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
324 float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
325 float u_umin = crossing_theta_u_min.second;
326 float u_umax = crossing_theta_u_max.second;
327 float v_vmin = crossing_theta_v_min.second;
328 float v_vmax = crossing_theta_v_max.second;
329 if ((u_umin < umin_roi) && (u_umax >= umin_roi) && (v_vmin < vmin_roi) && (v_vmax >= vmin_roi)) {
330 // The circle crosses only once each axis
331 //Case crossing once
332 delta_theta = theta_u_max - theta_v_max;
333 }
334 else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax >= vmin_roi)) {
335 // The circle crosses twice each axis
336 //Case crossing twice
337 delta_theta = (theta_v_min - theta_u_min) + (theta_u_max - theta_v_max);
338 }
339 else if ((u_umin < umin_roi) && (u_umax < umin_roi) && (v_vmin >= vmin_roi) && (v_vmax >= vmin_roi)) {
340 // The circle crosses the u-axis outside the roi
341 // so it is equivalent to the case of crossing only the left border
342 //Case left only
343 computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
344 }
345 else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmin_roi) && (v_vmax <= vmin_roi)) {
346 // The circle crosses the v-axis outside the roi
347 // so it is equivalent to the case of crossing only the top border
348 //Case top only
349 computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
350 }
351}
352
364void computeIntersectionsTopRight(const float &u_c, const float &v_c, const float &vmin_roi, const float &umax_roi,
365 const float &radius, float &delta_theta)
366{
367 const int val_2 = 2;
368 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
369 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
370 computePerpendicularAxesInters(u_c, v_c, radius, vmin_roi, umax_roi,
371 crossing_theta_u_min, crossing_theta_u_max,
372 crossing_theta_v_min, crossing_theta_v_max);
373 float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
374 float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
375 float u_umin = crossing_theta_u_min.second;
376 float u_umax = crossing_theta_u_max.second;
377 float v_vmin = crossing_theta_v_min.second;
378 float v_vmax = crossing_theta_v_max.second;
379 if ((u_umin <= umax_roi) && (v_vmin < vmin_roi) && (u_umax >= umax_roi) && (v_vmax >= vmin_roi)) {
380 // The circle crosses only once each axis and the center is below the top border
381 //Case crossing once
382 delta_theta = theta_v_max - theta_u_min;
383 if (delta_theta < 0) {
384 // The arc cannot be negative
385 delta_theta += 2.f * M_PI_FLOAT;
386 }
387 }
388 else if ((u_umin <= umax_roi) && (v_vmin >= vmin_roi) && (u_umax <= umax_roi) && (v_vmax >= vmin_roi)) {
389 // The circle crosses twice each axis
390 //Case crossing twice
391 delta_theta = (val_2 * M_PI_FLOAT) - ((theta_u_min - theta_u_max) + (theta_v_min - theta_v_max));
392 }
393 else if ((u_umin >= umax_roi) && (v_vmin >= vmin_roi) && (u_umax >= umax_roi) && (v_vmax >= vmin_roi)) {
394 // The circle crosses the u-axis outside the roi
395 // so it is equivalent to the case of crossing only the right border
396 //Case crossing right only
397 computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
398 }
399 else if ((u_umin <= umax_roi) && (v_vmin <= vmin_roi) && (u_umax <= umax_roi) && (v_vmax <= vmin_roi)) {
400 // The circle crosses the v-axis outside the roi
401 // so it is equivalent to the case of crossing only the top border
402 //Case crossing top only
403 computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
404 }
405}
406
418void computeIntersectionsBottomLeft(const float &u_c, const float &v_c, const float &umin_roi, const float &vmax_roi,
419 const float &radius, float &delta_theta)
420{
421 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
422 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
423 float crossing_u = vmax_roi; // We cross the u-axis of the RoI at which v-coordinate
424 float crossing_v = umin_roi; // We cross the v-axis of the RoI at which u-coordinate
425 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v,
426 crossing_theta_u_min, crossing_theta_u_max,
427 crossing_theta_v_min, crossing_theta_v_max);
428 float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
429 float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
430 float u_umin = crossing_theta_u_min.second;
431 float u_umax = crossing_theta_u_max.second;
432 float v_vmin = crossing_theta_v_min.second;
433 float v_vmax = crossing_theta_v_max.second;
434 if ((u_umin < umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmax_roi) && (v_vmax > vmax_roi)) {
435 // The circle crosses only once each axis
436 //Case crossing once
437 delta_theta = theta_v_min - theta_u_max;
438 }
439 else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
440 // The circle crosses twice each axis
441 //Case crossing twice
442 delta_theta = (theta_v_min - theta_u_max) + (theta_u_min - theta_v_max);
443 }
444 else if ((u_umin < umin_roi) && (u_umax < umin_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
445 // The circle crosses the u-axis outside the roi
446 // so it is equivalent to the case of crossing only the left border
447 //Case left only
448 computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
449 }
450 else if ((u_umin >= umin_roi) && (u_umax >= umin_roi) && (v_vmin >= vmax_roi) && (v_vmax >= vmax_roi)) {
451 // The circle crosses the v-axis outside the roi
452 // so it is equivalent to the case of crossing only the bottom border
453 //Case bottom only
454 computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
455 }
456}
457
469void computeIntersectionsBottomRight(const float &u_c, const float &v_c, const float &vmax_roi, const float &umax_roi,
470 const float &radius, float &delta_theta)
471{
472 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
473 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
474 float crossing_u = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
475 float crossing_v = umax_roi; // We cross the v-axis of the RoI at the maximum u-coordinate of the RoI
476 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v,
477 crossing_theta_u_min, crossing_theta_u_max,
478 crossing_theta_v_min, crossing_theta_v_max);
479 float theta_u_min = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
480 float theta_u_max = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
481 float u_umin = crossing_theta_u_min.second;
482 float u_umax = crossing_theta_u_max.second;
483 float v_vmin = crossing_theta_v_min.second;
484 float v_vmax = crossing_theta_v_max.second;
485 if ((u_umin <= umax_roi) && (u_umax > umax_roi) && (v_vmin <= vmax_roi) && (v_vmax > vmax_roi)) {
486 // The circle crosses only once each axis
487 //Case crossing once
488 delta_theta = theta_u_min - theta_v_min;
489 if (delta_theta < 0) {
490 // An arc length cannot be negative it means that theta_u_max was comprise in the bottom left quadrant of the circle
491 delta_theta += 2.f * M_PI_FLOAT;
492 }
493 }
494 else if ((u_umin <= umax_roi) && (u_umax <= umax_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
495 // The circle crosses twice each axis
496 //Case crossing twice
497 delta_theta = (2.f * M_PI_FLOAT) - ((theta_v_min - theta_v_max) + (theta_u_max - theta_u_min));
498 }
499 else if ((u_umin > umax_roi) && (u_umax > umax_roi) && (v_vmin <= vmax_roi) && (v_vmax <= vmax_roi)) {
500 // The circle crosses the u-axis outside the roi
501 // so it is equivalent to the case of crossing only the right border
502 //Case left only
503 computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
504 }
505 else if ((u_umin <= umax_roi) && (u_umax <= umax_roi) && (v_vmin > vmax_roi) && (v_vmax > vmax_roi)) {
506 // The circle crosses the v-axis outside the roi
507 // so it is equivalent to the case of crossing only the bottom border
508 //Case bottom only
509 computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
510 }
511}
512
525void computeIntersTopLeftBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &vmin_roi,
526 const float &vmax_roi, const float &radius, float &delta_theta)
527{
528 // Computing the intersections with the top and left axes
529 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
530 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
531 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
532 float crossing_v = umin_roi; // We cross the v-axis of the RoI at the minimum u-coordinate of the RoI
533 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_top, crossing_v,
534 crossing_theta_u_min, crossing_theta_u_max,
535 crossing_theta_v_min, crossing_theta_v_max);
536 float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
537 float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
538 float u_umin_top = crossing_theta_u_min.second;
539 float u_umax_top = crossing_theta_u_max.second;
540 float v_vmin = crossing_theta_v_min.second;
541 float v_vmax = crossing_theta_v_max.second;
542
543 // Computing the intersections with the bottom and left axes
544 float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
545 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_bottom, crossing_v,
546 crossing_theta_u_min, crossing_theta_u_max,
547 crossing_theta_v_min, crossing_theta_v_max);
548 float theta_u_min_bottom = crossing_theta_u_min.first;
549 float theta_u_max_bottom = crossing_theta_u_max.first;
550 float u_umin_bottom = crossing_theta_u_min.second;
551 float u_umax_bottom = crossing_theta_u_max.second;
552 if ((u_umin_top >= umin_roi) && (u_umin_bottom >= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
553 // case intersection top + left + bottom twice
554 delta_theta = (theta_v_min - theta_u_min_top) + (theta_u_max_top - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max);
555 }
556 else if ((u_umin_top <= umin_roi) && (v_vmin <= vmin_roi) && (u_umin_bottom <= umin_roi) && (v_vmax >= vmax_roi)) {
557 // case intersection top and bottom
558 delta_theta = (theta_u_max_top - theta_u_max_bottom);
559 }
560 else if ((u_umax_top <= umin_roi) && (u_umax_bottom <= umin_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
561 // case left only
562 computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
563 }
564 else if ((u_umax_bottom > umin_roi) && (v_vmin >= vmin_roi)) {
565 // case bottom/left corner
566 computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
567 }
568 else if ((u_umax_top > umin_roi) && (v_vmax <= vmax_roi)) {
569 // case top/left corner
570 computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
571 }
572}
573
586void computeIntersTopRightBottom(const float &u_c, const float &v_c, const float &umax_roi, const float &vmin_roi,
587 const float &vmax_roi, const float &radius, float &delta_theta)
588{
589 // Computing the intersections with the top and right axes
590 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
591 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
592 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
593 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
594 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_top, crossing_v,
595 crossing_theta_u_min, crossing_theta_u_max,
596 crossing_theta_v_min, crossing_theta_v_max);
597 float theta_u_min_top = crossing_theta_u_min.first, theta_v_min = crossing_theta_v_min.first;
598 float theta_u_max_top = crossing_theta_u_max.first, theta_v_max = crossing_theta_v_max.first;
599 float u_umin_top = crossing_theta_u_min.second;
600 float u_umax_top = crossing_theta_u_max.second;
601 float v_vmin = crossing_theta_v_min.second;
602 float v_vmax = crossing_theta_v_max.second;
603
604 // Computing the intersections with the bottom and right axes
605 float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
606 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_bottom, crossing_v,
607 crossing_theta_u_min, crossing_theta_u_max,
608 crossing_theta_v_min, crossing_theta_v_max);
609 float theta_u_min_bottom = crossing_theta_u_min.first;
610 float theta_u_max_bottom = crossing_theta_u_max.first;
611 float u_umin_bottom = crossing_theta_u_min.second;
612 float u_umax_bottom = crossing_theta_u_max.second;
613 bool crossOnceTopHor = (u_umin_top <= umax_roi) && (u_umax_top > umax_roi);
614 bool dontCrossVert = (v_vmin <= vmin_roi) && (v_vmax >= vmax_roi);
615 bool crossOnceBotHor = (u_umin_bottom <= umax_roi) && (u_umax_bottom > umax_roi);
616 if ((u_umax_top <= umax_roi) && (u_umax_bottom <= umax_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
617 // case intersection top + right + bottom twice
618 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));
619 }
620 else if (crossOnceTopHor && crossOnceBotHor && dontCrossVert) {
621 // case intersection top and bottom
622 delta_theta = (theta_u_max_top - theta_u_max_bottom);
623 }
624 else if ((u_umin_top >= umax_roi) && (u_umin_bottom >= umax_roi) && (v_vmin >= vmin_roi) && (v_vmax <= vmax_roi)) {
625 // case right only
626 computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
627 }
628 else if ((u_umin_bottom <= umax_roi) && (v_vmin >= vmin_roi)) {
629 // case bottom/right corner
630 computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
631 }
632 else if ((u_umin_top <= umax_roi) && (v_vmax <= vmax_roi)) {
633 // case top/right corner
634 computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
635 }
636}
637
649void computeIntersTopBottomOnly(const float &u_c, const float &v_c, const float &vmin_roi, const float &vmax_roi,
650 const float &radius, float &delta_theta)
651{
652 // Computing the two angles for which the u-axis is crossed at the top of the RoI
653 // v = vc - r sin(theta) because the v-axis goes down
654 // theta = asin((vc - vmin_roi)/r)
655 float theta_u_cross_top = std::asin((v_c - vmin_roi) / radius);
656 theta_u_cross_top = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross_top);
657 float theta_u_cross_top_2 = 0.f;
658 if (theta_u_cross_top > 0) {
659 theta_u_cross_top_2 = M_PI_FLOAT - theta_u_cross_top;
660 }
661 else {
662 theta_u_cross_top_2 = -M_PI_FLOAT - theta_u_cross_top;
663 }
664
665 // Computing the corresponding u-coordinates at which the u-axis is crossed
666 float u_ucross_top = u_c + (radius * std::cos(theta_u_cross_top));
667 float u_ucross_top_2 = u_c + (radius * std::cos(theta_u_cross_top_2));
668 // Sorting the outputs such as u(theta_u_cross_top_min) < u(theta_u_cross_top_max)
669 float theta_u_cross_top_min = 0.f, theta_u_cross_top_max = 0.f;
670 if (u_ucross_top < u_ucross_top_2) {
671 theta_u_cross_top_min = theta_u_cross_top;
672 theta_u_cross_top_max = theta_u_cross_top_2;
673 }
674 else {
675 theta_u_cross_top_min = theta_u_cross_top_2;
676 theta_u_cross_top_max = theta_u_cross_top;
677 }
678
679 // Computing the two angles for which the u-axis is crossed at the bottom of the RoI
680 // v = vc - r sin(theta) because the v-axis goes down
681 // theta = asin((vc - vmax_roi)/r)
682 float theta_u_cross_bottom = std::asin((v_c - vmax_roi) / radius);
683 theta_u_cross_bottom = vpMath::getAngleBetweenMinPiAndPi(theta_u_cross_bottom);
684 float theta_u_cross_bottom_2 = 0.f;
685 if (theta_u_cross_bottom > 0) {
686 theta_u_cross_bottom_2 = M_PI_FLOAT - theta_u_cross_bottom;
687 }
688 else {
689 theta_u_cross_bottom_2 = -M_PI_FLOAT - theta_u_cross_bottom;
690 }
691
692 // Computing the corresponding u-coordinates at which the u-axis is crossed
693 float u_ucross_bottom = u_c + (radius * std::cos(theta_u_cross_bottom));
694 float u_ucross_bottom_2 = u_c + (radius * std::cos(theta_u_cross_bottom_2));
695
696 // Sorting the outputs such as u(theta_u_cross_bottom_min) < u(theta_u_cross_bottom_max)
697 float theta_u_cross_bottom_min = 0.f, theta_u_cross_bottom_max = 0.f;
698 if (u_ucross_bottom < u_ucross_bottom_2) {
699 theta_u_cross_bottom_min = theta_u_cross_bottom;
700 theta_u_cross_bottom_max = theta_u_cross_bottom_2;
701 }
702 else {
703 theta_u_cross_bottom_min = theta_u_cross_bottom_2;
704 theta_u_cross_bottom_max = theta_u_cross_bottom;
705 }
706
707 // Computing the the length of the angular interval of the circle when it intersects
708 // only with the top and bottom borders of the Region of Interest (RoI)
709 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));
710}
711
724void computeIntersLeftRightTop(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
725 const float &vmin_roi, const float &radius, float &delta_theta)
726{
727 // Computing the intersections with the top and left axes
728 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
729 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
730 float crossing_u = vmin_roi; // We cross the u-axis of the RoI at the minimum v-coordinate of the RoI
731 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
732 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_left,
733 crossing_theta_u_min, crossing_theta_u_max,
734 crossing_theta_v_min, crossing_theta_v_max);
735 float theta_u_min = crossing_theta_u_min.first;
736 float theta_u_max = crossing_theta_u_max.first;
737 float u_umin = crossing_theta_u_min.second;
738 float u_umax = crossing_theta_u_max.second;
739 float theta_v_min_left = crossing_theta_v_min.first;
740 float theta_v_max_left = crossing_theta_v_max.first;
741 float v_vmin_left = crossing_theta_v_min.second;
742 float v_vmax_left = crossing_theta_v_max.second;
743
744 // Computing the intersections with the rigt and top axes
745 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
746 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_right,
747 crossing_theta_u_min, crossing_theta_u_max,
748 crossing_theta_v_min, crossing_theta_v_max);
749 float theta_v_min_right = crossing_theta_v_min.first;
750 float theta_v_max_right = crossing_theta_v_max.first;
751 float v_vmin_right = crossing_theta_v_min.second;
752 float v_vmax_right = crossing_theta_v_max.second;
753
754 if ((u_umin >= umin_roi) && (u_umax <= umax_roi) && (v_vmin_left >= vmin_roi) && (v_vmin_right >= vmin_roi)) {
755 // case intersection left + right + top twice
756 delta_theta = (theta_v_min_left - theta_u_min) + (theta_u_max - theta_v_min_right) + (theta_v_max_right - theta_v_max_left);
757 }
758 else if ((u_umin <= umin_roi) && (u_umax >= umax_roi) && (v_vmax_left >= vmin_roi) && (v_vmax_right >= vmin_roi)) {
759 // case intersection left + right
760 delta_theta = (theta_v_max_right - theta_v_max_left);
761 }
762 else if ((v_vmax_left <= vmin_roi) && (v_vmax_right <= vmin_roi) && (u_umin >= umin_roi) && (u_umax <= umax_roi)) {
763 // case top only
764 computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
765 }
766 else if ((u_umax >= umin_roi) && (v_vmax_left >= vmin_roi)) {
767 // case top/left corner
768 computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
769 }
770 else if ((u_umin <= umax_roi) && (v_vmax_right >= vmin_roi)) {
771 // case top/right corner
772 computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
773 }
774}
775
788void computeIntersLeftRightBottom(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
789 const float &vmax_roi, const float &radius, float &delta_theta)
790{
791 // Computing the intersections with the bottom and left axes
792 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
793 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
794 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
795 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
796 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_left,
797 crossing_theta_u_min, crossing_theta_u_max,
798 crossing_theta_v_min, crossing_theta_v_max);
799 float theta_u_min = crossing_theta_u_min.first;
800 float theta_u_max = crossing_theta_u_max.first;
801 float u_umin = crossing_theta_u_min.second;
802 float u_umax = crossing_theta_u_max.second;
803 float theta_v_min_left = crossing_theta_v_min.first;
804 float theta_v_max_left = crossing_theta_v_max.first;
805 float v_vmin_left = crossing_theta_v_min.second;
806 // --comment: float v_vmax_left equals crossing_theta_v_max dot second
807
808 // Computing the intersections with the bottom and right axes
809 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
810 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u, crossing_v_right,
811 crossing_theta_u_min, crossing_theta_u_max,
812 crossing_theta_v_min, crossing_theta_v_max);
813 float theta_v_min_right = crossing_theta_v_min.first;
814 float theta_v_max_right = crossing_theta_v_max.first;
815 float v_vmin_right = crossing_theta_v_min.second;
816 // --comment: float v_vmax_right equals crossing_theta_v_max dot second
817
818 if ((u_umin >= umin_roi) && (u_umax <= umax_roi) && (v_vmin_left <= vmax_roi) && (v_vmin_right <= vmax_roi)) {
819 // case intersection left + right + bottom twice
820 delta_theta = (theta_v_min_left - theta_v_min_right) + (theta_v_max_right - theta_u_max) + (theta_u_min - theta_v_max_left);
821 }
822 else if ((u_umin <= umin_roi) && (u_umax >= umax_roi) && (v_vmin_left <= vmax_roi) && (v_vmin_right <= vmax_roi)) {
823 // case intersection left + right
824 delta_theta = (theta_v_min_left - theta_v_min_right);
825 }
826 else if ((v_vmin_left >= vmax_roi) && (v_vmin_right >= vmax_roi) && (u_umin >= umin_roi) && (u_umax <= umax_roi)) {
827 // case bottom only
828 computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
829 }
830 else if ((u_umax >= umin_roi) && (v_vmin_right >= vmax_roi)) {
831 // case bottom/left corner
832 computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
833 }
834 else if ((u_umin <= umax_roi) && (v_vmin_right <= vmax_roi)) {
835 // case bottom/right corner
836 computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
837 }
838}
839
851void computeIntersectionsLeftRight(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
852 const float &radius, float &delta_theta)
853{
854 // Computing the two angles for which the v-axis is crossed at the left of the RoI
855 // umin_roi = u_c + r cos(theta)
856 // theta = acos((umin_roi - u_c)/r)
857 // theta_min = -theta_max
858 float theta_v_cross_left = std::acos((umin_roi - u_c) / radius);
859 theta_v_cross_left = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross_left);
860 float theta_v_cross_left_2 = -theta_v_cross_left;
861
862 // Computing the corresponding v-coordinates at which the v-axis is crossed
863 float v_vcross_left = v_c - (radius * std::sin(theta_v_cross_left));
864 float v_vcross_left_2 = v_c - (radius * std::sin(theta_v_cross_left_2));
865 // Sorting the outputs such as v(theta_v_cross_left_min) < v(theta_v_cross_left_max)
866 float theta_v_cross_left_min = 0.f, theta_v_cross_left_max = 0.f;
867 if (v_vcross_left < v_vcross_left_2) {
868 theta_v_cross_left_min = theta_v_cross_left;
869 theta_v_cross_left_max = theta_v_cross_left_2;
870 }
871 else {
872 theta_v_cross_left_min = theta_v_cross_left_2;
873 theta_v_cross_left_max = theta_v_cross_left;
874 }
875
876 // Computing the two angles for which the v-axis is crossed at the right of the RoI
877 // umax_roi = u_c + r cos(theta)
878 // theta = acos((umin_roi - u_c)/r)
879 // theta_min = -theta_max
880 float theta_v_cross_right = std::acos((umax_roi - u_c) / radius);
881 theta_v_cross_right = vpMath::getAngleBetweenMinPiAndPi(theta_v_cross_right);
882 float theta_v_cross_right_2 = -theta_v_cross_right;
883
884 // Computing the corresponding v-coordinates at which the v-axis is crossed
885 float v_vcross_right = v_c - (radius * std::sin(theta_v_cross_right));
886 float v_vcross_right_2 = v_c - (radius * std::sin(theta_v_cross_right_2));
887
888 // Sorting the outputs such as v(theta_v_cross_right_min) < v(theta_v_cross_right_max)
889 float theta_v_cross_right_min = 0.f, theta_v_cross_right_max = 0.f;
890 if (v_vcross_right < v_vcross_right_2) {
891 theta_v_cross_right_min = theta_v_cross_right;
892 theta_v_cross_right_max = theta_v_cross_right_2;
893 }
894 else {
895 theta_v_cross_right_min = theta_v_cross_right_2;
896 theta_v_cross_right_max = theta_v_cross_right;
897 }
898
899 // Computing the the length of the angular interval of the circle when it intersects
900 // only with the top and bottom borders of the Region of Interest (RoI)
901 delta_theta = (theta_v_cross_left_min - theta_v_cross_right_min) + (theta_v_cross_right_max - theta_v_cross_left_max);
902}
903
917void computeIntersectionsAllAxes(const float &u_c, const float &v_c, const float &umin_roi, const float &umax_roi,
918 const float &vmin_roi, const float &vmax_roi, const float &radius, float &delta_theta)
919{
920 // Computing the intersections with the top and left axes
921 std::pair<float, float> crossing_theta_u_min, crossing_theta_u_max;
922 std::pair<float, float> crossing_theta_v_min, crossing_theta_v_max;
923 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
924 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
925 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_top, crossing_v_left,
926 crossing_theta_u_min, crossing_theta_u_max,
927 crossing_theta_v_min, crossing_theta_v_max);
928 float theta_u_min_top = crossing_theta_u_min.first;
929 float theta_u_max_top = crossing_theta_u_max.first;
930 float theta_v_min_left = crossing_theta_v_min.first;
931 float theta_v_max_left = crossing_theta_v_max.first;
932
933 // Computing the intersections with the bottom and right axes
934 float crossing_u_bottom = vmax_roi; // We cross the u-axis of the RoI at the maximum v-coordinate of the RoI
935 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
936 computePerpendicularAxesInters(u_c, v_c, radius, crossing_u_bottom, crossing_v_right,
937 crossing_theta_u_min, crossing_theta_u_max,
938 crossing_theta_v_min, crossing_theta_v_max);
939 float theta_u_min_bottom = crossing_theta_u_min.first;
940 float theta_u_max_bottom = crossing_theta_u_max.first;
941 float theta_v_min_right = crossing_theta_v_min.first;
942 float theta_v_max_right = crossing_theta_v_max.first;
943 delta_theta = (theta_v_min_left - theta_u_min_top) + (theta_u_max_top - theta_v_min_right);
944 delta_theta += (theta_v_max_right - theta_u_max_bottom) + (theta_u_min_bottom - theta_v_max_left);
945}
946
947float vpImageCircle::computeAngularCoverageInRoI(const vpRect &roi, const float &roundingTolerance) const
948{
949 float delta_theta = 0.f;
950 vpImagePoint center = m_center;
951 float u_c = static_cast<float>(center.get_u());
952 float v_c = static_cast<float>(center.get_v());
953 float radius = m_radius;
954 float roi_w = static_cast<float>(roi.getWidth());
955 float roi_h = static_cast<float>(roi.getHeight());
956 vpImagePoint topLeft = roi.getTopLeft();
957 float umin_roi = static_cast<float>(topLeft.get_u());
958 float vmin_roi = static_cast<float>(topLeft.get_v());
959 float umax_roi = umin_roi + roi_w;
960 float vmax_roi = vmin_roi + roi_h;
961 bool touchLeftBorder = (u_c - radius) <= umin_roi;
962 bool touchRightBorder = (u_c + radius) >= umax_roi;
963 bool touchTopBorder = (v_c - radius) <= vmin_roi;
964 bool touchBottomBorder = (v_c + radius) >= vmax_roi;
965 bool isHorizontallyOK = ((!touchLeftBorder) && (!touchRightBorder));
966 bool isVerticallyOK = ((!touchTopBorder) && (!touchBottomBorder));
967 if (isHorizontallyOK && isVerticallyOK && roi.isInside(m_center)) {
968 // Easy case
969 // The circle has its center in the image and its radius is not too great
970 // to make it fully contained in the RoI
971 delta_theta = 2.f * M_PI_FLOAT;
972 }
973 else if (touchBottomBorder && (!touchLeftBorder) && (!touchRightBorder) && (!touchTopBorder)) {
974 // Touches/intersects only the bottom border of the RoI
975 computeIntersBottomBorder(v_c, vmax_roi, radius, delta_theta);
976 }
977 else if ((!touchBottomBorder) && touchLeftBorder && (!touchRightBorder) && (!touchTopBorder)) {
978 // Touches/intersects only the left border of the RoI
979 computeIntersectionsLeftBorder(u_c, umin_roi, radius, delta_theta);
980 }
981 else if ((!touchBottomBorder) && (!touchLeftBorder) && touchRightBorder && (!touchTopBorder)) {
982 // Touches/intersects only the right border of the RoI
983 computeIntersectionsRightBorder(u_c, umax_roi, radius, delta_theta);
984 }
985 else if ((!touchBottomBorder) && (!touchLeftBorder) && (!touchRightBorder) && touchTopBorder) {
986 // Touches/intersects only the top border of the RoI
987 computeIntersectionsTopBorder(v_c, vmin_roi, radius, delta_theta);
988 }
989 else if (touchBottomBorder && touchLeftBorder && (!touchRightBorder) && (!touchTopBorder)) {
990 // Touches/intersects the bottom and left borders of the RoI
991 computeIntersectionsBottomLeft(u_c, v_c, umin_roi, vmax_roi, radius, delta_theta);
992 }
993 else if (touchBottomBorder && (!touchLeftBorder) && touchRightBorder && (!touchTopBorder)) {
994 // Touches/intersects the bottom and right borders of the RoI
995 computeIntersectionsBottomRight(u_c, v_c, vmax_roi, umax_roi, radius, delta_theta);
996 }
997 else if ((!touchBottomBorder) && touchLeftBorder && (!touchRightBorder) && touchTopBorder) {
998 // Touches/intersects the top and left borders of the RoI
999 computeIntersectionsTopLeft(u_c, v_c, umin_roi, vmin_roi, radius, delta_theta);
1000 }
1001 else if ((!touchBottomBorder) && (!touchLeftBorder) && touchRightBorder && touchTopBorder) {
1002 // Touches/intersects the top and right borders of the RoI
1003 computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
1004 }
1005 else if (touchBottomBorder && touchTopBorder && touchLeftBorder && (!touchRightBorder)) {
1006 // Touches/intersects the top, left and bottom borders of the RoI
1007 computeIntersTopLeftBottom(u_c, v_c, umin_roi, vmin_roi, vmax_roi, radius, delta_theta);
1008 }
1009 else if (touchBottomBorder && touchTopBorder && (!touchLeftBorder) && touchRightBorder) {
1010 // Touches/intersects the top, right and bottom borders of the RoI
1011 computeIntersTopRightBottom(u_c, v_c, umax_roi, vmin_roi, vmax_roi, radius, delta_theta);
1012 }
1013 else if (touchBottomBorder && touchTopBorder && (!touchLeftBorder) && (!touchRightBorder)) {
1014 // Touches/intersects the top and bottom borders of the RoI
1015 computeIntersTopBottomOnly(u_c, v_c, vmin_roi, vmax_roi, radius, delta_theta);
1016 }
1017 else if ((!touchBottomBorder) && touchTopBorder && touchLeftBorder && touchRightBorder) {
1018 // Touches/intersects the top, left and right borders of the RoI
1019 computeIntersLeftRightTop(u_c, v_c, umin_roi, umax_roi, vmin_roi, radius, delta_theta);
1020 }
1021 else if (touchBottomBorder && (!touchTopBorder) && touchLeftBorder && touchRightBorder) {
1022 // Touches/intersects the bottom, left and right borders of the RoI
1023 computeIntersLeftRightBottom(u_c, v_c, umin_roi, umax_roi, vmax_roi, radius, delta_theta);
1024 }
1025 else if (touchLeftBorder && touchRightBorder && (!touchTopBorder) && (!touchBottomBorder)) {
1026 // Touches/intersects the bottom, left and right borders of the RoI
1027 computeIntersectionsLeftRight(u_c, v_c, umin_roi, umax_roi, radius, delta_theta);
1028 }
1029 else if (touchLeftBorder && touchRightBorder && touchTopBorder && touchBottomBorder) {
1030 // Touches/intersects each axis
1031 computeIntersectionsAllAxes(u_c, v_c, umin_roi, umax_roi, vmin_roi, vmax_roi, radius, delta_theta);
1032 }
1033 else {
1034 std::cerr << "touchLeft = " << (touchLeftBorder ? "true" : "false") << "\ttouchRight = " << (touchRightBorder ? "true" : "false") << std::endl;
1035 std::cerr << "touchTop = " << (touchTopBorder ? "true" : "false") << "\ttouchBottom = " << (touchBottomBorder ? "true" : "false") << std::endl;
1036 std::cerr << "u_c = " << u_c << "\tv_c = " << v_c << "\tradius = " << radius << std::endl;
1037 std::cerr << "umin_roi = " << umin_roi << "\tumax_roi = " << umax_roi << std::endl;
1038 std::cerr << "vmin_roi = " << vmin_roi << "\tvmax_roi = " << vmax_roi << std::endl << std::flush;
1039 throw(vpException(vpException::fatalError, "This case should never happen. Please contact Inria to make fix the problem"));
1040 }
1041
1042 if ((delta_theta < 0) || (delta_theta >(2.f * M_PI_FLOAT))) { // Needed since M_PI_FLOAT is used
1043 float rest = vpMath::modulo(delta_theta, 2.f * M_PI_FLOAT);
1044 if ((rest < roundingTolerance) && ((delta_theta < -M_PI_FLOAT) || (delta_theta > M_PI_FLOAT))) {
1045 // If the angle is a negative multiple of 2.f * M_PI_FLOAT we consider it to be 2.f * M_PI_FLOAT
1046 delta_theta = 2.f * M_PI_FLOAT;
1047 }
1048 else {
1049 //Otherwise, it corresponds to delta_theta modulo 2.f * M_PI_FLOAT
1050 delta_theta = rest;
1051 }
1052 }
1053
1054 return delta_theta;
1055}
1056
1057float vpImageCircle::computeArcLengthInRoI(const vpRect &roi, const float &roundingTolerance) const
1058{
1059 float delta_theta = computeAngularCoverageInRoI(roi, roundingTolerance);
1060 return delta_theta * m_radius;
1061}
1062
1063#if (VISP_CXX_STANDARD == VISP_CXX_STANDARD_98)
1064namespace
1065{
1066void incrementIfIsInMask(const vpImage<bool> &mask, const int &width, const int &height, const int &x, const int &y,
1067 unsigned int &count);
1068
1069// Increment the counter if the considered pixel (x, y) is in the mask image
1070void incrementIfIsInMask(const vpImage<bool> &mask, const int &width, const int &height, const int &x, const int &y,
1071 unsigned int &count)
1072{
1073 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1074 // The pixel is outside the limit of the mask
1075 return;
1076 }
1077 if (mask[y][x]) {
1078 // Increment only if the pixel value of the mask is true
1079 ++count;
1080 }
1081}
1082}
1083#endif
1084
1086{
1087 const float xm = static_cast<float>(m_center.get_u()), ym = static_cast<float>(m_center.get_v());
1088 const float r_float = static_cast<float>(m_radius);
1089 const int width = static_cast<int>(mask.getWidth());
1090 const int height = static_cast<int>(mask.getHeight());
1091
1092#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
1093 // Increment the counter if the considered pixel (x, y) is in the mask image
1094 auto incrementIfIsInMask = [](const vpImage<bool> &mask_, const int &width_, const int &height_, const int &x_, const int &y_,
1095 unsigned int &count_) {
1096 if ((x_ < 0) || (y_ < 0) || (x_ >= width_) || (y_ >= height_)) {
1097 // The pixel is outside the limit of the mask
1098 return;
1099 }
1100 if (mask_[y_][x_]) {
1101 // Increment only if the pixel value of the mask is true
1102 ++count_;
1103 }
1104 };
1105#endif
1106 unsigned int count = 0; // Count the number of pixels of the circle whose value in the mask is true
1107
1108 const float thetaStop = M_PI_2_FLOAT;
1109 float theta = 0;
1110 int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
1111 int y1 = 0, y2 = 0, y3 = 0, y4 = 0;
1112 while (theta < thetaStop) {
1113 float cos_theta = std::cos(theta);
1114 float sin_theta = std::sin(theta);
1115 float rcos_pos = r_float * cos_theta;
1116 float rsin_pos = r_float * sin_theta;
1117 x1 = static_cast<int>(xm + rcos_pos); // theta
1118 y1 = static_cast<int>(ym + rsin_pos); // theta
1119 x2 = static_cast<int>(xm - rsin_pos); // theta + pi
1120 y2 = static_cast<int>(ym + rcos_pos); // theta + pi
1121 x3 = static_cast<int>(xm - rcos_pos); // theta + pi/2
1122 y3 = static_cast<int>(ym - rsin_pos); // theta + pi/2
1123 x4 = static_cast<int>(xm + rsin_pos); // theta + pi
1124 y4 = static_cast<int>(ym - rcos_pos); // theta + pi
1125 incrementIfIsInMask(mask, width, height, x1, y1, count);
1126 incrementIfIsInMask(mask, width, height, x2, y2, count);
1127 incrementIfIsInMask(mask, width, height, x3, y3, count);
1128 incrementIfIsInMask(mask, width, height, x4, y4, count);
1129
1130 // Looking for dtheta such as either x or 1 increments of 1 pix exactly
1131 // Using series expansion, we get that if we want to have an increment of
1132 // 1 pixel for the derivative along x (resp. y), we have to respect the
1133 // following formulae
1134 float dthetaCosPos = 1.f / (r_float * cos_theta);
1135 float dthetaCosNeg = -1.f / (r_float * cos_theta);
1136 float dthetaSinPos = 1.f / (r_float * sin_theta);
1137 float dthetaSinNeg = -1.f / (r_float * sin_theta);
1138 float dthetaPos = 0.f;
1139 if ((sin_theta < 0.f) && (cos_theta > 0.f)) {
1140 // --comment: dTheta lesseq -1/r sin(theta) and dTheta lesseq 1/r cos(theta)
1141 dthetaPos = std::min<float>(dthetaCosPos, dthetaSinNeg);
1142 }
1143 else if ((sin_theta > 0.f) && (cos_theta < 0.f)) {
1144 // --comment: dTheta lesseq 1/r sin(theta) and dTheta lesseq -1/r cos(theta)
1145 dthetaPos = std::min<float>(dthetaCosNeg, dthetaSinPos);
1146 }
1147 else if ((sin_theta < 0.f) && (cos_theta < 0.f)) {
1148 // --comment: dTheta lesseq -1/r sin(theta) and dTheta lesseq -1/r cos(theta)
1149 dthetaPos = std::min<float>(dthetaCosNeg, dthetaSinNeg);
1150 }
1151 else if ((sin_theta > 0.f) && (cos_theta > 0.f)) {
1152 // --comment: dTheta lesseq 1/r sin(theta) and dTheta lesseq 1/r cos(theta)
1153 dthetaPos = std::min<float>(dthetaCosPos, dthetaSinPos);
1154 }
1155 else if (vpMath::equal(sin_theta, 0.f) && (!vpMath::equal(cos_theta, 0.f))) {
1156 // --comment: dTheta eq -1 / r cos(theta) or dTheta eq 1 / r cos(theta)
1157 if (cos_theta > 0.f) {
1158 dthetaPos = dthetaCosNeg;
1159 }
1160 else {
1161 dthetaPos = dthetaCosPos;
1162 }
1163 }
1164 else if ((!vpMath::equal(sin_theta, 0.f)) && vpMath::equal(cos_theta, 0.f)) {
1165 // --comment: dTheta eq -1 / r sin(theta) or dTheta eq 1 / r sin(theta)
1166 if (sin_theta > 0.f) {
1167 dthetaPos = dthetaSinNeg;
1168 }
1169 else {
1170 dthetaPos = dthetaSinPos;
1171 }
1172 }
1173 theta += dthetaPos;
1174 }
1175 return count;
1176}
1177
1179{
1180 return m_center;
1181}
1182
1184{
1185 return m_radius;
1186}
1187
1189{
1190 double radius = static_cast<double>(m_radius);
1191 vpRect bbox(m_center - vpImagePoint(radius, radius), 2 * radius, 2 * radius);
1192 return bbox;
1193}
1194
1196{
1197 const int val_4 = 4;
1198 return (m_radius * m_radius) / val_4;
1199}
1200
1202{
1203 const int val_4 = 4;
1204 return (m_radius * m_radius) / val_4;
1205}
1206
1208{
1209 return 0.;
1210}
1211
1213{
1214 bool sameCenter = (a.getCenter() == b.getCenter());
1215 bool sameRadius = std::abs(a.getRadius() - b.getRadius()) < 1e-6;
1216
1217 return (sameCenter && sameRadius);
1218}
1219
1220bool operator!=(const vpImageCircle &a, const vpImageCircle &b)
1221{
1222 return !(a == b);
1223}
1224END_VISP_NAMESPACE
friend VISP_EXPORT bool operator==(const vpImageCircle &a, const vpImageCircle &b)
Overloaded equality operator to compare two vpImageCircle objects.
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ fatalError
Fatal error.
Definition vpException.h:72
Class that defines a 2D circle in an image.
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 ...
double get_u() const
double get_v() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
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:470
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:119
vpImagePoint getTopLeft() const
Definition vpRect.h:199
double getHeight() const
Definition vpRect.h:166