1 /*
2 * Copyright (C) 2015 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.geometry.estimators;
17
18 import com.irurueta.geometry.Circle;
19 import com.irurueta.geometry.Point2D;
20 import com.irurueta.numerical.robust.RobustEstimatorException;
21 import com.irurueta.numerical.robust.RobustEstimatorMethod;
22
23 import java.util.List;
24
25 /**
26 * This is an abstract class for algorithms to robustly find the best circle
27 * that fits in a collection of 2D points.
28 * Implementations of this class should be able to detect and discard outliers
29 * in order to find the best solution.
30 */
31 @SuppressWarnings("DuplicatedCode")
32 public abstract class CircleRobustEstimator {
33 /**
34 * Minimum number of 2D points required to estimate a circle.
35 */
36 public static final int MINIMUM_SIZE = 3;
37
38 /**
39 * Default amount of progress variation before notifying a change in
40 * estimation progress. By default, this is set to 5%.
41 */
42 public static final float DEFAULT_PROGRESS_DELTA = 0.05f;
43
44 /**
45 * Minimum allowed value for progress delta.
46 */
47 public static final float MIN_PROGRESS_DELTA = 0.0f;
48
49 /**
50 * Maximum allowed value for progress delta.
51 */
52 public static final float MAX_PROGRESS_DELTA = 1.0f;
53
54 /**
55 * Constant defining default confidence of the estimated result, which is
56 * 99%. This means that with a probability of 99% estimation will be
57 * accurate because chosen sub-samples will be inliers.
58 */
59 public static final double DEFAULT_CONFIDENCE = 0.99;
60
61 /**
62 * Default maximum allowed number of iterations.
63 */
64 public static final int DEFAULT_MAX_ITERATIONS = 5000;
65
66 /**
67 * Minimum allowed confidence value.
68 */
69 public static final double MIN_CONFIDENCE = 0.0;
70
71 /**
72 * Maximum allowed confidence value.
73 */
74 public static final double MAX_CONFIDENCE = 1.0;
75
76 /**
77 * Minimum allowed number of iterations.
78 */
79 public static final int MIN_ITERATIONS = 1;
80
81 /**
82 * Default robust estimator method when none is provided.
83 */
84 public static final RobustEstimatorMethod DEFAULT_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
85
86 /**
87 * Listener to be notified of events such as when estimation starts, ends
88 * or its progress significantly changes.
89 */
90 protected CircleRobustEstimatorListener listener;
91
92 /**
93 * Indicates if this estimator is locked because an estimation is being
94 * computed.
95 */
96 protected volatile boolean locked;
97
98 /**
99 * Amount of progress variation before notifying a progress change during
100 * estimation.
101 */
102 protected float progressDelta;
103
104 /**
105 * Amount of confidence expressed as a value between 0.0 and 1.0 (which is
106 * equivalent to 100%). The amount of confidence indicates the probability
107 * that the estimated result is correct. Usually this value will be close
108 * to 1.0, but not exactly 1.0.
109 */
110 protected double confidence;
111
112 /**
113 * Maximum allowed number of iterations. When the maximum number of
114 * iterations is exceeded, result will not be available, however an
115 * approximate result will be available for retrieval.
116 */
117 protected int maxIterations;
118
119 /**
120 * List of points to be used to estimate a circle. Provided list must have
121 * a size greater or equal than MINIMUM_SIZE.
122 */
123 protected List<Point2D> points;
124
125 /**
126 * Constructor.
127 */
128 protected CircleRobustEstimator() {
129 progressDelta = DEFAULT_PROGRESS_DELTA;
130 confidence = DEFAULT_CONFIDENCE;
131 maxIterations = DEFAULT_MAX_ITERATIONS;
132 }
133
134 /**
135 * Constructor.
136 *
137 * @param listener listener to be notified of events such as when estimation
138 * starts, ends or its progress significantly changes.
139 */
140 protected CircleRobustEstimator(final CircleRobustEstimatorListener listener) {
141 this.listener = listener;
142 progressDelta = DEFAULT_PROGRESS_DELTA;
143 confidence = DEFAULT_CONFIDENCE;
144 maxIterations = DEFAULT_MAX_ITERATIONS;
145 }
146
147 /**
148 * Constructor with points.
149 *
150 * @param points 2D points to estimate a circle.
151 * @throws IllegalArgumentException if provided list of points don't have
152 * a size greater or equal than MINIMUM_SIZE.
153 */
154 protected CircleRobustEstimator(final List<Point2D> points) {
155 progressDelta = DEFAULT_PROGRESS_DELTA;
156 confidence = DEFAULT_CONFIDENCE;
157 maxIterations = DEFAULT_MAX_ITERATIONS;
158 internalSetPoints(points);
159 }
160
161 /**
162 * Constructor.
163 *
164 * @param points 2D points to estimate a circle.
165 * @param listener listener to be notified of events such as when estimation
166 * starts, ends or its progress significantly changes.
167 * @throws IllegalArgumentException if provided list of points don't have
168 * a size greater or equal than MINIMUM_SIZE.
169 */
170 protected CircleRobustEstimator(final CircleRobustEstimatorListener listener, final List<Point2D> points) {
171 this.listener = listener;
172 progressDelta = DEFAULT_PROGRESS_DELTA;
173 confidence = DEFAULT_CONFIDENCE;
174 maxIterations = DEFAULT_MAX_ITERATIONS;
175 internalSetPoints(points);
176 }
177
178
179 /**
180 * Returns reference to listener to be notified of events such as when
181 * estimation starts, ends or its progress significantly changes.
182 *
183 * @return listener to be notified of events.
184 */
185 public CircleRobustEstimatorListener getListener() {
186 return listener;
187 }
188
189 /**
190 * Sets listener to be notified of events such as when estimation starts,
191 * ends or its progress significantly changes.
192 *
193 * @param listener listener to be notified of events.
194 * @throws LockedException if robust estimator is locked.
195 */
196 public void setListener(final CircleRobustEstimatorListener listener) throws LockedException {
197 if (isLocked()) {
198 throw new LockedException();
199 }
200 this.listener = listener;
201 }
202
203 /**
204 * Indicates whether listener has been provided and is available for
205 * retrieval.
206 *
207 * @return true if available, false otherwise.
208 */
209 public boolean isListenerAvailable() {
210 return listener != null;
211 }
212
213 /**
214 * Indicates if this instance is locked because estimation is being computed
215 *
216 * @return true if locked, false otherwise.
217 */
218 public boolean isLocked() {
219 return locked;
220 }
221
222 /**
223 * Returns amount of progress variation before notifying a progress change
224 * during estimation.
225 *
226 * @return amount of progress variation before notifying a progress change
227 * during estimation.
228 */
229 public float getProgressDelta() {
230 return progressDelta;
231 }
232
233 /**
234 * Sets amount of progress variation before notifying a progress change
235 * during estimation.
236 *
237 * @param progressDelta amount of progress variation before notifying a
238 * progress change during estimation.
239 * @throws IllegalArgumentException if progress delta is less than zero or
240 * greater than 1.
241 * @throws LockedException if this estimator is locked because an estimation
242 * is being computed.
243 */
244 public void setProgressDelta(final float progressDelta) throws LockedException {
245 if (isLocked()) {
246 throw new LockedException();
247 }
248 if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) {
249 throw new IllegalArgumentException();
250 }
251 this.progressDelta = progressDelta;
252 }
253
254 /**
255 * Returns amount of confidence expressed as a value between 0.0 and 1.0
256 * (which is equivalent to 100%). The amount of confidence indicates the
257 * probability that the estimated result is correct. Usually this value will
258 * be close to 1.0, but not exactly 1.0.
259 *
260 * @return amount of confidence as a value between 0.0 and 1.0.
261 */
262 public double getConfidence() {
263 return confidence;
264 }
265
266 /**
267 * Sets amount of confidence expressed as a value between 0.0 and 1.0 (which
268 * is equivalent to 100%). The amount of confidence indicates the
269 * probability that the estimated result is correct. Usually this value will
270 * be close to 1.0, but not exactly 1.0.
271 *
272 * @param confidence confidence to be set as a value between 0.0 and 1.0.
273 * @throws IllegalArgumentException if provided value is not between 0.0 and
274 * 1.0.
275 * @throws LockedException if this estimator is locked because an estimator
276 * is being computed.
277 */
278 public void setConfidence(final double confidence) throws LockedException {
279 if (isLocked()) {
280 throw new LockedException();
281 }
282 if (confidence < MIN_CONFIDENCE || confidence > MAX_CONFIDENCE) {
283 throw new IllegalArgumentException();
284 }
285 this.confidence = confidence;
286 }
287
288 /**
289 * Returns maximum allowed number of iterations. If maximum allowed number
290 * of iterations is achieved without converging to a result when calling
291 * estimate(), a RobustEstimatorException will be raised.
292 *
293 * @return maximum allowed number of iterations.
294 */
295 public int getMaxIterations() {
296 return maxIterations;
297 }
298
299 /**
300 * Sets maximum allowed number of iterations. When the maximum number of
301 * iterations is exceeded, result will not be available, however an
302 * approximate result will be available for retrieval.
303 *
304 * @param maxIterations maximum allowed number of iterations to be set.
305 * @throws IllegalArgumentException if provided value is less than 1.
306 * @throws LockedException if this estimator is locked because an estimation
307 * is being computed.
308 */
309 public void setMaxIterations(final int maxIterations) throws LockedException {
310 if (isLocked()) {
311 throw new LockedException();
312 }
313 if (maxIterations < MIN_ITERATIONS) {
314 throw new IllegalArgumentException();
315 }
316 this.maxIterations = maxIterations;
317 }
318
319 /**
320 * Returns list of points to be used to estimate a circle.
321 * Provided list must have a size greater or equal than MINIMUM_SIZE.
322 *
323 * @return list of points to be used to estimate a circle.
324 */
325 public List<Point2D> getPoints() {
326 return points;
327 }
328
329 /**
330 * Sets list of points to be used to estimate a circle.
331 * Provided list must have a size greater or equal than MINIMUM_SIZE.
332 *
333 * @param points list of points to be used to estimate a circle.
334 * @throws IllegalArgumentException if provided list of points don't have
335 * a size greater or equal than MINIMUM_SIZE.
336 * @throws LockedException if estimator is locked because a computation is
337 * already in progress.
338 */
339 public void setPoints(final List<Point2D> points) throws LockedException {
340 if (isLocked()) {
341 throw new LockedException();
342 }
343 internalSetPoints(points);
344 }
345
346 /**
347 * Indicates if estimator is ready to start the circle estimation.
348 * This is true when a minimum if MINIMUM_SIZE points are available.
349 *
350 * @return true if estimator is ready, false otherwise.
351 */
352 public boolean isReady() {
353 return points != null && points.size() >= MINIMUM_SIZE;
354 }
355
356 /**
357 * Returns quality scores corresponding to each point.
358 * The larger the score value the better the quality of the point measure.
359 * This implementation always returns null.
360 * Subclasses using quality scores must implement proper behaviour.
361 *
362 * @return quality scores corresponding to each point.
363 */
364 public double[] getQualityScores() {
365 return null;
366 }
367
368 /**
369 * Sets quality scores corresponding to each point.
370 * The larger the score value the better the quality of the point sample.
371 * This implementation makes no action.
372 * Subclasses using quality scores must implement proper behaviour.
373 *
374 * @param qualityScores quality scores corresponding to each sampled point.
375 * @throws LockedException if robust estimator is locked because an
376 * estimation is already in progress.
377 * @throws IllegalArgumentException if provided quality scores length is
378 * smaller than MINIMUM_SIZE (i.e. 3 samples).
379 */
380 public void setQualityScores(final double[] qualityScores) throws LockedException {
381 }
382
383 /**
384 * Creates a circle robust estimator based on 2D point samples and using
385 * provided robust estimator method.
386 *
387 * @param method method of a robust estimator algorithm to estimate best
388 * circle.
389 * @return an instance of a circle robust estimator.
390 */
391 public static CircleRobustEstimator create(final RobustEstimatorMethod method) {
392 return switch (method) {
393 case LMEDS -> new LMedSCircleRobustEstimator();
394 case MSAC -> new MSACCircleRobustEstimator();
395 case PROSAC -> new PROSACCircleRobustEstimator();
396 case PROMEDS -> new PROMedSCircleRobustEstimator();
397 default -> new RANSACCircleRobustEstimator();
398 };
399 }
400
401 /**
402 * Creates a circle robust estimator based on 2D point samples and using
403 * provided points and robust estimator method.
404 *
405 * @param points 2D points to estimate a circle.
406 * @param method method of a robust estimator algorithm to estimate best
407 * circle.
408 * @return an instance of a circle robust estimator.
409 * @throws IllegalArgumentException if provided list of points don't have a
410 * size greater or equal than MINIMUM_SIZE.
411 */
412 public static CircleRobustEstimator create(
413 final List<Point2D> points, final RobustEstimatorMethod method) {
414 return switch (method) {
415 case LMEDS -> new LMedSCircleRobustEstimator(points);
416 case MSAC -> new MSACCircleRobustEstimator(points);
417 case PROSAC -> new PROSACCircleRobustEstimator(points);
418 case PROMEDS -> new PROMedSCircleRobustEstimator(points);
419 default -> new RANSACCircleRobustEstimator(points);
420 };
421 }
422
423 /**
424 * Creates a circle robust estimator based on 2D point samples and using
425 * provided listener.
426 *
427 * @param listener listener to be notified of events such as when estimation
428 * starts, ends or its progress significantly changes.
429 * @param method method of a robust estimator algorithm to estimate best
430 * circle.
431 * @return an instance of a circle robust estimator.
432 */
433 public static CircleRobustEstimator create(
434 final CircleRobustEstimatorListener listener,
435 final RobustEstimatorMethod method) {
436 return switch (method) {
437 case LMEDS -> new LMedSCircleRobustEstimator(listener);
438 case MSAC -> new MSACCircleRobustEstimator(listener);
439 case PROSAC -> new PROSACCircleRobustEstimator(listener);
440 case PROMEDS -> new PROMedSCircleRobustEstimator(listener);
441 default -> new RANSACCircleRobustEstimator(listener);
442 };
443 }
444
445 /**
446 * Creates a circle robust estimator based on 2D point samples and using
447 * provided listener and points.
448 *
449 * @param listener listener to be notified of events such as when estimation
450 * starts, ends or its progress significantly changes.
451 * @param points 2D points to estimate a circle.
452 * @param method method of a robust estimator algorithm to estimate best
453 * circle.
454 * @return an instance of a circle robust estimator.
455 * @throws IllegalArgumentException if provided list of points don't have a
456 * size greater or equal than MINIMUM_SIZE.
457 */
458 public static CircleRobustEstimator create(
459 final CircleRobustEstimatorListener listener, final List<Point2D> points,
460 final RobustEstimatorMethod method) {
461 return switch (method) {
462 case LMEDS -> new LMedSCircleRobustEstimator(listener, points);
463 case MSAC -> new MSACCircleRobustEstimator(listener, points);
464 case PROSAC -> new PROSACCircleRobustEstimator(listener, points);
465 case PROMEDS -> new PROMedSCircleRobustEstimator(listener, points);
466 default -> new RANSACCircleRobustEstimator(listener, points);
467 };
468 }
469
470 /**
471 * Creates a circle robust estimator based on 2D point samples and using
472 * provided robust estimator method.
473 *
474 * @param qualityScores quality scores corresponding to each provided point.
475 * @param method method of a robust estimator algorithm to estimate best
476 * circle.
477 * @return an instance of a circle robust estimator.
478 * @throws IllegalArgumentException if provided quality scores length is
479 * smaller than MINIMUM_SIZE (i.e. 3 points).
480 */
481 public static CircleRobustEstimator create(
482 final double[] qualityScores, final RobustEstimatorMethod method) {
483 return switch (method) {
484 case LMEDS -> new LMedSCircleRobustEstimator();
485 case MSAC -> new MSACCircleRobustEstimator();
486 case PROSAC -> new PROSACCircleRobustEstimator(qualityScores);
487 case PROMEDS -> new PROMedSCircleRobustEstimator(qualityScores);
488 default -> new RANSACCircleRobustEstimator();
489 };
490 }
491
492 /**
493 * Creates a circle robust estimator based on 2D point samples and using
494 * provided points and robust estimator method.
495 *
496 * @param points 2D points to estimate a circle.
497 * @param qualityScores quality scores corresponding to each provided point.
498 * @param method method of a robust estimator algorithm to estimate best
499 * circle.
500 * @return an instance of a circle robust estimator.
501 * @throws IllegalArgumentException if provided list of points don't have
502 * the same size as the list of provided quality scores, or it their size
503 * is not greater or equal than MINIMUM_SIZE.
504 */
505 public static CircleRobustEstimator create(
506 final List<Point2D> points, final double[] qualityScores, final RobustEstimatorMethod method) {
507 return switch (method) {
508 case LMEDS -> new LMedSCircleRobustEstimator(points);
509 case MSAC -> new MSACCircleRobustEstimator(points);
510 case PROSAC -> new PROSACCircleRobustEstimator(points, qualityScores);
511 case PROMEDS -> new PROMedSCircleRobustEstimator(points, qualityScores);
512 default -> new RANSACCircleRobustEstimator(points);
513 };
514 }
515
516 /**
517 * Creates a circle robust estimator based on 2D point samples and using
518 * provided listener.
519 *
520 * @param listener listener to be notified of events such as when estimation
521 * starts, ends or its progress significantly changes.
522 * @param qualityScores quality scores corresponding to each provided point.
523 * @param method method of a robust estimator algorithm to estimate best
524 * circle.
525 * @return an instance of a circle robust estimator.
526 * @throws IllegalArgumentException if provided quality scores length is
527 * smaller than MINIMUM_SIZE (i.e. 3 points).
528 */
529 public static CircleRobustEstimator create(
530 final CircleRobustEstimatorListener listener, final double[] qualityScores,
531 final RobustEstimatorMethod method) {
532 return switch (method) {
533 case LMEDS -> new LMedSCircleRobustEstimator(listener);
534 case MSAC -> new MSACCircleRobustEstimator(listener);
535 case PROSAC -> new PROSACCircleRobustEstimator(listener, qualityScores);
536 case PROMEDS -> new PROMedSCircleRobustEstimator(listener, qualityScores);
537 default -> new RANSACCircleRobustEstimator(listener);
538 };
539 }
540
541 /**
542 * Creates a circle robust estimator based on 2D point samples and using
543 * provided listener and points.
544 *
545 * @param listener listener to be notified of events such as when estimation
546 * starts, ends or its progress significantly changes.
547 * @param points 2D points to estimate a circle.
548 * @param qualityScores quality scores corresponding to each provided point.
549 * @param method method of a robust estimator algorithm to estimate best
550 * circle.
551 * @return an instance of a circle robust estimator.
552 * @throws IllegalArgumentException if provided list of points don't have
553 * the same size as the list of provided quality scores, or it their size
554 * is not greater or equal than MINIMUM_SIZE.
555 */
556 public static CircleRobustEstimator create(
557 final CircleRobustEstimatorListener listener, final List<Point2D> points,
558 final double[] qualityScores, final RobustEstimatorMethod method) {
559 return switch (method) {
560 case LMEDS -> new LMedSCircleRobustEstimator(listener, points);
561 case MSAC -> new MSACCircleRobustEstimator(listener, points);
562 case PROSAC -> new PROSACCircleRobustEstimator(listener, points,
563 qualityScores);
564 case PROMEDS -> new PROMedSCircleRobustEstimator(listener, points,
565 qualityScores);
566 default -> new RANSACCircleRobustEstimator(listener, points);
567 };
568 }
569
570 /**
571 * Creates a circle robust estimator based on 2D point samples and using
572 * default robust estimator method.
573 *
574 * @return an instance of a circle robust estimator.
575 */
576 public static CircleRobustEstimator create() {
577 return create(DEFAULT_ROBUST_METHOD);
578 }
579
580 /**
581 * Creates a circle robust estimator based on 2D point samples and using
582 * provided points and default robust estimator method.
583 *
584 * @param points 2D points to estimate a circle.
585 * @return an instance of a circle robust estimator.
586 * @throws IllegalArgumentException if provided list of points don't have a
587 * size greater or equal than MINIMUM_SIZE.
588 */
589 public static CircleRobustEstimator create(final List<Point2D> points) {
590 return create(points, DEFAULT_ROBUST_METHOD);
591 }
592
593 /**
594 * Creates a circle robust estimator based on 2D point samples and using
595 * provided listener and default robust estimator method.
596 *
597 * @param listener listener to be notified of events such as when estimation
598 * starts, ends or its progress significantly changes.
599 * @return an instance of a circle robust estimator.
600 */
601 public static CircleRobustEstimator create(final CircleRobustEstimatorListener listener) {
602 return create(listener, DEFAULT_ROBUST_METHOD);
603 }
604
605 /**
606 * Creates a circle robust estimator based on 2D point samples and using
607 * provided listener and points and default robust estimator method.
608 *
609 * @param listener listener to be notified of events such as when estimation
610 * starts, ends or its progress significantly changes.
611 * @param points 2D points to estimate a circle.
612 * @return an instance of a circle robust estimator.
613 * @throws IllegalArgumentException if provided list of points don't have a
614 * size greater or equal than MINIMUM_SIZE.
615 */
616 public static CircleRobustEstimator create(final CircleRobustEstimatorListener listener,
617 final List<Point2D> points) {
618 return create(listener, points, DEFAULT_ROBUST_METHOD);
619 }
620
621 /**
622 * Creates a circle robust estimator based on 2D point samples and using
623 * default robust estimator method.
624 *
625 * @param qualityScores quality scores corresponding to each provided point
626 * @return an instance of a circle robust estimator.
627 * @throws IllegalArgumentException if provided quality scores length is
628 * smaller than MINIMUM_SIZE (i.e. 3 points).
629 */
630 public static CircleRobustEstimator create(final double[] qualityScores) {
631 return create(qualityScores, DEFAULT_ROBUST_METHOD);
632 }
633
634 /**
635 * Creates a circle robust estimator based on 2D point samples and using
636 * provided points and default estimator method.
637 *
638 * @param points 2D points to estimate a circle.
639 * @param qualityScores quality scores corresponding to each provided point
640 * @return an instance of a circle robust estimator.
641 * @throws IllegalArgumentException if provided list of points don't have
642 * the same size as the list of provided quality scores, or if their size
643 * is not greater or equal than MINIMUM_SIZE.
644 */
645 public static CircleRobustEstimator create(
646 final List<Point2D> points, final double[] qualityScores) {
647 return create(points, qualityScores, DEFAULT_ROBUST_METHOD);
648 }
649
650 /**
651 * Creates a circle robust estimator based on 2D point samples and using
652 * provided listener and default estimator method.
653 *
654 * @param listener listener to be notified of events such as when estimation
655 * starts, ends or its progress significantly changes.
656 * @param qualityScores quality scores corresponding to each provided point
657 * @return an instance of a circle robust estimator.
658 * @throws IllegalArgumentException if provided quality scores length is
659 * smaller than MINIMUM_SIZE (i.e. 3 points).
660 */
661 public static CircleRobustEstimator create(
662 final CircleRobustEstimatorListener listener, final double[] qualityScores) {
663 return create(listener, qualityScores, DEFAULT_ROBUST_METHOD);
664 }
665
666 /**
667 * Creates a circle robust estimator based on 2D point samples and using
668 * provided listener and points and default estimator method.
669 *
670 * @param listener listener to be notified of events such as when estimation
671 * starts, ends or its progress significantly changes.
672 * @param points 2D points to estimate a circle.
673 * @param qualityScores quality scores corresponding to each provided point
674 * @return an instance of a circle robust estimator.
675 * @throws IllegalArgumentException if provided list of points don't have
676 * the same size as the list of provided quality scores, or if their size
677 * is not greater or equal than MINIMUM_SIZE.
678 */
679 public static CircleRobustEstimator create(
680 final CircleRobustEstimatorListener listener, final List<Point2D> points, final double[] qualityScores) {
681 return create(listener, points, qualityScores, DEFAULT_ROBUST_METHOD);
682 }
683
684 /**
685 * Estimates a circle using a robust estimator and the best set of 2D points
686 * that fit into the locus of the estimated circle found using the robust
687 * estimator.
688 *
689 * @return a circle.
690 * @throws LockedException if robust estimator is locked because an
691 * estimation is already in progress.
692 * @throws NotReadyException if provided input data is not enough to start
693 * the estimation.
694 * @throws RobustEstimatorException if estimation fails for any reason
695 * (i.e. numerical instability, no solution available, etc).
696 */
697 public abstract Circle estimate() throws LockedException, NotReadyException, RobustEstimatorException;
698
699 /**
700 * Returns method being used for robust estimation.
701 *
702 * @return method being used for robust estimation.
703 */
704 public abstract RobustEstimatorMethod getMethod();
705
706 /**
707 * Internal method to set lists of points to be used to estimate a circle.
708 * This method does not check whether estimator is locked or not.
709 *
710 * @param points list of points to be used to estimate a circle.
711 * @throws IllegalArgumentException if provided list of points doesn't have
712 * a size greater or equal than MINIMUM_SIZE.
713 */
714 private void internalSetPoints(final List<Point2D> points) {
715 if (points.size() < MINIMUM_SIZE) {
716 throw new IllegalArgumentException();
717 }
718 this.points = points;
719 }
720
721 /**
722 * Computes the residual between a circle and a point.
723 *
724 * @param c a circle.
725 * @param point a 2D point.
726 * @return residual.
727 */
728 protected double residual(final Circle c, final Point2D point) {
729 point.normalize();
730
731 return c.getDistance(point);
732 }
733 }