View Javadoc
1   /*
2    * Copyright (C) 2017 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.algebra.Matrix;
19  import com.irurueta.geometry.EuclideanTransformation3D;
20  import com.irurueta.geometry.Point3D;
21  import com.irurueta.geometry.refiners.EuclideanTransformation3DRefiner;
22  import com.irurueta.numerical.robust.InliersData;
23  import com.irurueta.numerical.robust.RobustEstimatorException;
24  import com.irurueta.numerical.robust.RobustEstimatorMethod;
25  
26  import java.util.List;
27  
28  /**
29   * This is an abstract class to robustly find the best Euclidean transformation
30   * for collections mof matching 3D points.
31   * Implementations of this class should be able to detect and discard outliers
32   * in order to find the best solution.
33   */
34  @SuppressWarnings("DuplicatedCode")
35  public abstract class EuclideanTransformation3DRobustEstimator {
36      /**
37       * Minimum number of matched points required to estimate an Euclidean 2D
38       * transformation.
39       */
40      public static final int MINIMUM_SIZE = EuclideanTransformation3DEstimator.MINIMUM_SIZE;
41  
42      /**
43       * For some point configurations a solution can be found with only 3 points.
44       */
45      public static final int WEAK_MINIMUM_SIZE = EuclideanTransformation3DEstimator.WEAK_MINIMUM_SIZE;
46  
47      /**
48       * Default amount of progress variation before notifying a change in
49       * estimation progress. By default, this is set to 5%.
50       */
51      public static final float DEFAULT_PROGRESS_DELTA = 0.05f;
52  
53      /**
54       * Minimum allowed value for progress delta.
55       */
56      public static final float MIN_PROGRESS_DELTA = 0.0f;
57  
58      /**
59       * Maximum allowed value for progress delta.
60       */
61      public static final float MAX_PROGRESS_DELTA = 1.0f;
62  
63      /**
64       * Constant defining default confidence of the estimated result, which is
65       * 99%. This means that with a probability of 99% estimation will be
66       * accurate because chosen sub-samples will be inliers.
67       */
68      public static final double DEFAULT_CONFIDENCE = 0.99;
69  
70      /**
71       * Default maximum allowed number of iterations.
72       */
73      public static final int DEFAULT_MAX_ITERATIONS = 5000;
74  
75      /**
76       * Minimum allowed confidence value.
77       */
78      public static final double MIN_CONFIDENCE = 0.0;
79  
80      /**
81       * Maximum allowed confidence value.
82       */
83      public static final double MAX_CONFIDENCE = 1.0;
84  
85      /**
86       * Minimum allowed number of iterations.
87       */
88      public static final int MIN_ITERATIONS = 1;
89  
90      /**
91       * Indicates that is refined by default using Levenberg-Marquardt
92       * fitting algorithm over found inliers.
93       */
94      public static final boolean DEFAULT_REFINE_RESULT = true;
95  
96      /**
97       * Indicates that covariance is not kept by default after refining result.
98       */
99      public static final boolean DEFAULT_KEEP_COVARIANCE = false;
100 
101     /**
102      * Default robust estimator method when none is provided.
103      */
104     public static final RobustEstimatorMethod DEFAULT_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
105 
106     /**
107      * Listener to be notified of events such as when estimation starts, ends
108      * or its progress significantly changes.
109      */
110     protected EuclideanTransformation3DRobustEstimatorListener listener;
111 
112     /**
113      * Indicates if this estimator is locked because an estimation is being
114      * computed.
115      */
116     protected boolean locked;
117 
118     /**
119      * Amount of progress variation before notifying a progress change during
120      * estimation.
121      */
122     protected float progressDelta;
123 
124     /**
125      * Amount of confidence expressed as a value between 0.0 and 1.0 (which is
126      * equivalent to 100%). The amount of confidence indicates the probability
127      * that the estimated result is correct. Usually this value will be close
128      * to 1.0, but not exactly 1.0.
129      */
130     protected double confidence;
131 
132     /**
133      * Maximum allowed number of iterations. When the maximum number of
134      * iterations is exceeded, result will not be available, however an
135      * approximate result will be available for retrieval.
136      */
137     protected int maxIterations;
138 
139     /**
140      * Data related to inliers found after estimation.
141      */
142     protected InliersData inliersData;
143 
144     /**
145      * Indicates whether result must be refined using Levenberg-Marquardt
146      * fitting algorithm over found inliers.
147      * If true, inliers will be computed and kept in any implementation
148      * regardless of the settings.
149      */
150     protected boolean refineResult;
151 
152     /**
153      * Indicates whether covariance must be kept after refining result.
154      * This setting is only taken into account if result is refined.
155      */
156     private boolean keepCovariance;
157 
158     /**
159      * Estimated covariance of estimated 2D Euclidean transformation.
160      * This is only available when result has been refined and covariance is
161      * kept.
162      */
163     private Matrix covariance;
164 
165     /**
166      * List of points to be used to estimate an Euclidean 3D transformation.
167      * Each point in the list of input points must be matched with the
168      * corresponding point in the list of output points located at the same
169      * position. Hence, both input points and output points must have the same
170      * size, and their size must be greater or equal than MINIMUM_SIZE.
171      */
172     protected List<Point3D> inputPoints;
173 
174     /**
175      * List of points to be used to estimate an Euclidean 3D transformation.
176      * Each point in the lis tof output points must be matched with the
177      * corresponding point in the list of input points located at the same
178      * position. Hence, both input points and output points must have the same
179      * size, and their size must be greater or equal than MINIMUM_SIZE.
180      */
181     protected List<Point3D> outputPoints;
182 
183     /**
184      * Indicates whether estimation can start with only 3 points or not.
185      * True allows 3 points, false requires 4.
186      */
187     private boolean weakMinimumSizeAllowed;
188 
189     /**
190      * Constructor.
191      */
192     protected EuclideanTransformation3DRobustEstimator() {
193         progressDelta = DEFAULT_PROGRESS_DELTA;
194         confidence = DEFAULT_CONFIDENCE;
195         maxIterations = DEFAULT_MAX_ITERATIONS;
196         refineResult = DEFAULT_REFINE_RESULT;
197         keepCovariance = DEFAULT_KEEP_COVARIANCE;
198     }
199 
200     /**
201      * Constructor.
202      *
203      * @param listener listener to be notified of events such as when estimation
204      *                 starts, ends or its progress significantly changes.
205      */
206     protected EuclideanTransformation3DRobustEstimator(
207             final EuclideanTransformation3DRobustEstimatorListener listener) {
208         this();
209         this.listener = listener;
210     }
211 
212     /**
213      * Constructor with lists of points to be used to estimate an Euclidean 3D
214      * transformation.
215      * Points in the list located at the same position are considered to be
216      * matched. Hence, both lists must have the same size, and their size must
217      * be greater or equal than MINIMUM_SIZE.
218      *
219      * @param inputPoints  list of input points to be used to estimate an
220      *                     Euclidean 3D transformation.
221      * @param outputPoints list of output points to be used to estimate an
222      *                     Euclidean 3D transformation.
223      * @throws IllegalArgumentException if provided lists of points don't have
224      *                                  the same size or their size is smaller than MINIMUM_SIZE.
225      */
226     protected EuclideanTransformation3DRobustEstimator(
227             final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
228         this();
229         internalSetPoints(inputPoints, outputPoints);
230     }
231 
232     /**
233      * Constructor with listener and lists of points to be used to estimate an
234      * Euclidean 3D transformation.
235      * Points in the list located at the same position are considered to be
236      * matched. Hence, both lists must have the same size, and their size must
237      * be greater or equal than MINIMUM_SIZE.
238      *
239      * @param listener     listener to be notified of events such as when estimation
240      *                     starts, ends or its progress significantly changes.
241      * @param inputPoints  list of input points to be used to estimate an
242      *                     Euclidean 3D transformation.
243      * @param outputPoints list of output points to be used to estimate an
244      *                     Euclidean 3D transformation.
245      * @throws IllegalArgumentException if provided lists of points don't have
246      *                                  the same size or their size is smaller than MINIMUM_SIZE.
247      */
248     protected EuclideanTransformation3DRobustEstimator(
249             final EuclideanTransformation3DRobustEstimatorListener listener,
250             final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
251         this(listener);
252         internalSetPoints(inputPoints, outputPoints);
253     }
254 
255     /**
256      * Constructor.
257      *
258      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
259      */
260     protected EuclideanTransformation3DRobustEstimator(
261             final boolean weakMinimumSizeAllowed) {
262         this();
263         this.weakMinimumSizeAllowed = weakMinimumSizeAllowed;
264     }
265 
266     /**
267      * Constructor.
268      *
269      * @param listener               listener to be notified of events such as when estimation
270      *                               starts, ends or its progress significantly changes.
271      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
272      */
273     protected EuclideanTransformation3DRobustEstimator(
274             final EuclideanTransformation3DRobustEstimatorListener listener, final boolean weakMinimumSizeAllowed) {
275         this();
276         this.listener = listener;
277         this.weakMinimumSizeAllowed = weakMinimumSizeAllowed;
278     }
279 
280     /**
281      * Constructor with lists of points to be used to estimate an Euclidean 3D
282      * transformation.
283      * Points in the list located at the same position are considered to be
284      * matched. Hence, both lists must have the same size, and their size must
285      * be greater or equal than MINIMUM_SIZE.
286      *
287      * @param inputPoints            list of input points to be used to estimate an
288      *                               Euclidean 3D transformation.
289      * @param outputPoints           list of output points to be used to estimate an
290      *                               Euclidean 3D transformation.
291      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
292      * @throws IllegalArgumentException if provided lists of points don't have
293      *                                  the same size or their size is smaller than MINIMUM_SIZE.
294      */
295     protected EuclideanTransformation3DRobustEstimator(
296             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final boolean weakMinimumSizeAllowed) {
297         this();
298         this.weakMinimumSizeAllowed = weakMinimumSizeAllowed;
299         internalSetPoints(inputPoints, outputPoints);
300     }
301 
302     /**
303      * Constructor with listener and lists of points to be used to estimate an
304      * Euclidean 3D transformation.
305      * Points in the list located at the same position are considered to be
306      * matched. Hence, both lists must have the same size, and their size must
307      * be greater or equal than MINIMUM_SIZE.
308      *
309      * @param listener               listener to be notified of events such as when estimation
310      *                               starts, ends or its progress significantly changes.
311      * @param inputPoints            list of input points to be used to estimate an
312      *                               Euclidean 3D transformation.
313      * @param outputPoints           list of output points to be used to estimate an
314      *                               Euclidean 3D transformation.
315      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
316      * @throws IllegalArgumentException if provided lists of points don't have
317      *                                  the same size or their size is smaller than MINIMUM_SIZE.
318      */
319     protected EuclideanTransformation3DRobustEstimator(
320             final EuclideanTransformation3DRobustEstimatorListener listener,
321             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final boolean weakMinimumSizeAllowed) {
322         this(listener);
323         this.weakMinimumSizeAllowed = weakMinimumSizeAllowed;
324         internalSetPoints(inputPoints, outputPoints);
325     }
326 
327     /**
328      * Returns list of input points to be used to estimate an Euclidean 3D
329      * transformation.
330      * Each point in the list of input points must be matched with the
331      * corresponding point in the list of output points located at the same
332      * position. Hence, both input points and output points must have the same
333      * size, and their size must be greater or equal than MINIMUM_SIZE.
334      *
335      * @return list of input points to be used to estimate an Euclidean 3D
336      * transformation.
337      */
338     public List<Point3D> getInputPoints() {
339         return inputPoints;
340     }
341 
342     /**
343      * Returns list of output points to be used to estimate an Euclidean 3D
344      * transformation.
345      * Each point in the list of output points must be matched with the
346      * corresponding point in the list of input points located at the same
347      * position. Hence, both input points and output points must have the same
348      * size, and their size must be greater or equal than MINIMUM_SIZE.
349      *
350      * @return list of output points to be used to estimate an Euclidean 3D
351      * transformation.
352      */
353     public List<Point3D> getOutputPoints() {
354         return outputPoints;
355     }
356 
357     /**
358      * Sets list of points to be used to estimate an Euclidean 3D
359      * transformation.
360      * Points in the list located at the same position are considered to be
361      * matched. Hence, both lists must have the same size, and their size must
362      * be greater or equal than MINIMUM_SIZE.
363      *
364      * @param inputPoints  list of input points to be used to estimate an
365      *                     Euclidean 3D transformation.
366      * @param outputPoints list of output points to be used to estimate an
367      *                     Euclidean 3D transformation.
368      * @throws IllegalArgumentException if provided lists of points don't have
369      *                                  the same size or their size is smaller than MINIMUM_SIZE.
370      * @throws LockedException          if estimator is locked because a computation is
371      *                                  already in progress.
372      */
373     public void setPoints(final List<Point3D> inputPoints, final List<Point3D> outputPoints) throws LockedException {
374         if (isLocked()) {
375             throw new LockedException();
376         }
377         internalSetPoints(inputPoints, outputPoints);
378     }
379 
380     /**
381      * Indicates if estimator is ready to start the Euclidean 3D transformation
382      * estimation.
383      * This is true when input data (i.e. lists of matched points) are provided
384      * and a minimum of MINIMUM_SIZE points are available.
385      *
386      * @return true if estimator is ready, false otherwise.
387      */
388     public boolean isReady() {
389         return inputPoints != null && outputPoints != null && inputPoints.size() == outputPoints.size()
390                 && inputPoints.size() >= getMinimumPoints();
391     }
392 
393     /**
394      * Returns quality scores corresponding to each pair of matched points.
395      * The larger the score value the better the quality of the matching.
396      * This implementation always returns null.
397      * Subclasses using quality scores must implement proper behaviour.
398      *
399      * @return quality scores corresponding to each pair of matched points.
400      */
401     public double[] getQualityScores() {
402         return null;
403     }
404 
405     /**
406      * Sets quality scores corresponding to each pair of matched points.
407      * The larger the score value the better the quality of the matching.
408      * This implementation makes no action.
409      * Subclasses using quality scores must implement proper behaviour.
410      *
411      * @param qualityScores quality scores corresponding to each pair of matched
412      *                      points.
413      * @throws LockedException          if robust estimator is locked because an
414      *                                  estimation is already in progress.
415      * @throws IllegalArgumentException if provided quality scores length is
416      *                                  smaller than MINIMUM_SIZE (i.e. 3 samples).
417      */
418     public void setQualityScores(final double[] qualityScores) throws LockedException {
419     }
420 
421     /**
422      * Returns reference to listener to be notified of events such as when
423      * estimation starts, ends or its progress significantly changes.
424      *
425      * @return listener to be notified of events.
426      */
427     public EuclideanTransformation3DRobustEstimatorListener getListener() {
428         return listener;
429     }
430 
431     /**
432      * Sets listener to be notified of events such as when estimation starts,
433      * ends or its progress significantly changes.
434      *
435      * @param listener listener to be notified of events.
436      * @throws LockedException if robust estimator is locked.
437      */
438     public void setListener(final EuclideanTransformation3DRobustEstimatorListener listener) throws LockedException {
439         if (isLocked()) {
440             throw new LockedException();
441         }
442         this.listener = listener;
443     }
444 
445     /**
446      * Indicates whether listener has been provided and is available for
447      * retrieval.
448      *
449      * @return true if available, false otherwise.
450      */
451     public boolean isListenerAvailable() {
452         return listener != null;
453     }
454 
455     /**
456      * Indicates whether estimation can start with only 3 points or not.
457      *
458      * @return true allows 3 points, false requires 4.
459      */
460     public boolean isWeakMinimumSizeAllowed() {
461         return weakMinimumSizeAllowed;
462     }
463 
464     /**
465      * Specifies whether estimation can start with only 3 points or not.
466      *
467      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
468      * @throws LockedException if estimator is locked.
469      */
470     public void setWeakMinimumSizeAllowed(final boolean weakMinimumSizeAllowed) throws LockedException {
471         if (isLocked()) {
472             throw new LockedException();
473         }
474         this.weakMinimumSizeAllowed = weakMinimumSizeAllowed;
475     }
476 
477     /**
478      * Required minimum number of point correspondences to start the estimation.
479      * Can be either 3 or 4.
480      *
481      * @return minimum number of point correspondences.
482      */
483     public int getMinimumPoints() {
484         return weakMinimumSizeAllowed ? WEAK_MINIMUM_SIZE : MINIMUM_SIZE;
485     }
486 
487     /**
488      * Indicates if this instance is locked because estimation is being
489      * computed.
490      *
491      * @return true if locked, false otherwise.
492      */
493     public boolean isLocked() {
494         return locked;
495     }
496 
497     /**
498      * Returns amount of progress variation before notifying a progress change
499      * during estimation.
500      *
501      * @return amount of progress variation before notifying a progress change
502      * during estimation.
503      */
504     public float getProgressDelta() {
505         return progressDelta;
506     }
507 
508     /**
509      * Sets amount of progress variation before notifying a progress change
510      * during estimation.
511      *
512      * @param progressDelta amount of progress variation before notifying a
513      *                      progress change during estimation.
514      * @throws IllegalArgumentException if progress delta is less than zero or
515      *                                  greater than 1.
516      * @throws LockedException          if this estimator is locked because an estimation
517      *                                  is being computed.
518      */
519     public void setProgressDelta(final float progressDelta) throws LockedException {
520         if (isLocked()) {
521             throw new LockedException();
522         }
523         if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) {
524             throw new IllegalArgumentException();
525         }
526         this.progressDelta = progressDelta;
527     }
528 
529     /**
530      * Returns amount of confidence expressed as a value between 0.0 and 1.0
531      * (which is equivalent to 100%). The amount of confidence indicates the
532      * probability that the estimated result is correct. Usually this value will
533      * be close to 1.0, but not exactly 1.0.
534      *
535      * @return amount of confidence as a value between 0.0 and 1.0.
536      */
537     public double getConfidence() {
538         return confidence;
539     }
540 
541     /**
542      * Sets amount of confidence expressed as a value between 0.0 and 1.0 (which
543      * is equivalent to 100%). The amount of confidence indicates the
544      * probability that the estimated result is correct. Usually this value will
545      * be close to 1.0, but not exactly 1.0.
546      *
547      * @param confidence confidence to be set as a value between 0.0 and 1.0.
548      * @throws IllegalArgumentException if provided value is not between 0.0 and
549      *                                  1.0.
550      * @throws LockedException          if this estimator is locked because an estimator
551      *                                  is being computed.
552      */
553     public void setConfidence(final double confidence) throws LockedException {
554         if (isLocked()) {
555             throw new LockedException();
556         }
557         if (confidence < MIN_CONFIDENCE || confidence > MAX_CONFIDENCE) {
558             throw new IllegalArgumentException();
559         }
560         this.confidence = confidence;
561     }
562 
563     /**
564      * Returns maximum allowed number of iterations. If maximum allowed number
565      * of iterations is achieved without converging to a result when calling
566      * estimate(), a RobustEstimatorException will be raised.
567      *
568      * @return maximum allowed number of iterations.
569      */
570     public int getMaxIterations() {
571         return maxIterations;
572     }
573 
574     /**
575      * Sets maximum allowed number of iterations. When the maximum number of
576      * iterations is exceeded, result will not be available, however an
577      * approximate result will be available for retrieval.
578      *
579      * @param maxIterations maximum allowed number of iterations to be set.
580      * @throws IllegalArgumentException if provided value is less than 1.
581      * @throws LockedException          if this estimator is locked because an estimation
582      *                                  is being computed.
583      */
584     public void setMaxIterations(final int maxIterations) throws LockedException {
585         if (isLocked()) {
586             throw new LockedException();
587         }
588         if (maxIterations < MIN_ITERATIONS) {
589             throw new IllegalArgumentException();
590         }
591         this.maxIterations = maxIterations;
592     }
593 
594     /**
595      * Gets data related to inliers found after estimation.
596      *
597      * @return data related to inliers found after estimation.
598      */
599     public InliersData getInliersData() {
600         return inliersData;
601     }
602 
603     /**
604      * Indicates whether result must be refined using Levenberg-Marquardt
605      * fitting algorithm over found inliers.
606      * If ture, inliers will be computed and kept in any implementation
607      * regardless of the settings.
608      *
609      * @return true to refine result, false to simply use result found by
610      * robust estimator without further refining.
611      */
612     public boolean isResultRefined() {
613         return refineResult;
614     }
615 
616     /**
617      * Specifies whether result must be refined using Levenberg-Marquardt
618      * fitting algorithm over found inliers.
619      *
620      * @param refineResult true to refine result, false to simply use result
621      *                     found by robust estimator without further refining.
622      * @throws LockedException if estimator is locked.
623      */
624     public void setResultRefined(final boolean refineResult) throws LockedException {
625         if (isLocked()) {
626             throw new LockedException();
627         }
628         this.refineResult = refineResult;
629     }
630 
631     /**
632      * Indicates whether covariance must be kept after refining result.
633      * This setting is only taken into account if result is refined.
634      *
635      * @return true if covariance must be kept after refining result, false
636      * otherwise.
637      */
638     public boolean isCovarianceKept() {
639         return keepCovariance;
640     }
641 
642     /**
643      * Specifies whether covariance must be kept after refining result.
644      * This setting is only taken into account if result is refined.
645      *
646      * @param keepCovariance true if covariance must be kept after refining
647      *                       result, false otherwise.
648      * @throws LockedException if estimator is locked.
649      */
650     public void setCovarianceKept(final boolean keepCovariance) throws LockedException {
651         if (isLocked()) {
652             throw new LockedException();
653         }
654         this.keepCovariance = keepCovariance;
655     }
656 
657     /**
658      * Gets estimated covariance of estimated 3D point if available.
659      * This is only available when result has been refined and covariance is
660      * kept.
661      *
662      * @return estimated covariance or null.
663      */
664     public Matrix getCovariance() {
665         return covariance;
666     }
667 
668     /**
669      * Estimates an Euclidean 3D transformation using a robust estimator and the
670      * best set of matched 3D point correspondences found using the robust
671      * estimator.
672      *
673      * @return an Euclidean 3D transformation.
674      * @throws LockedException          if robust estimator is locked because an
675      *                                  estimation is already in progress.
676      * @throws NotReadyException        if provided input data is not enough to start
677      *                                  the estimation.
678      * @throws RobustEstimatorException if estimation fails for any reason
679      *                                  (i.e. numerical instability, no solution available, etc).
680      */
681     public abstract EuclideanTransformation3D estimate() throws LockedException, NotReadyException,
682             RobustEstimatorException;
683 
684     /**
685      * Returns method being used for robust estimation.
686      *
687      * @return method being used for robust estimation.
688      */
689     public abstract RobustEstimatorMethod getMethod();
690 
691 
692     /**
693      * Creates an Euclidean 3D transformation estimator based on 3D point
694      * correspondences and using provided robust estimator method.
695      *
696      * @param method method of a robust estimator algorithm to estimate
697      *               the best Euclidean 3D transformation.
698      * @return an instance of Euclidean 3D transformation estimator.
699      */
700     public static EuclideanTransformation3DRobustEstimator create(final RobustEstimatorMethod method) {
701         return switch (method) {
702             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator();
703             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator();
704             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator();
705             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator();
706             default -> new RANSACEuclideanTransformation3DRobustEstimator();
707         };
708     }
709 
710     /**
711      * Creates an Euclidean 3D transformation estimator based on 3D point
712      * correspondences and using provided estimator method.
713      *
714      * @param inputPoints  list of input points to be used to estimate an
715      *                     Euclidean 3D transformation.
716      * @param outputPoints list of output points to be used to estimate an
717      *                     Euclidean 3D transformation.
718      * @param method       method of a robust estimator algorithm to estimate the best
719      *                     Euclidean 3D transformation.
720      * @return an instance of Euclidean 3D transformation estimator.
721      * @throws IllegalArgumentException if provided lists of points don't have
722      *                                  the same size or their size is smaller than MINIMUM_SIZE.
723      */
724     public static EuclideanTransformation3DRobustEstimator create(
725             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final RobustEstimatorMethod method) {
726         return switch (method) {
727             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
728             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
729             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
730             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
731             default -> new RANSACEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
732         };
733     }
734 
735     /**
736      * Creates an Euclidean 3D transformation estimator based on 3D point
737      * correspondences and using provided robust estimator method.
738      *
739      * @param listener listener to be notified of events such as when estimation
740      *                 starts, ends or its progress significantly changes.
741      * @param method   method of a robust estimator algorithm to estimate the best
742      *                 Euclidean 3D transformation.
743      * @return an instance of Euclidean 3D transformation estimator.
744      */
745     public static EuclideanTransformation3DRobustEstimator create(
746             final EuclideanTransformation3DRobustEstimatorListener listener, final RobustEstimatorMethod method) {
747         return switch (method) {
748             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(listener);
749             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(listener);
750             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(listener);
751             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(listener);
752             default -> new RANSACEuclideanTransformation3DRobustEstimator(listener);
753         };
754     }
755 
756     /**
757      * Creates an Euclidean 3D transformation estimator based on 3D point
758      * correspondences and using provided robust estimator method.
759      *
760      * @param listener     listener to be notified of events such as when estimation
761      *                     starts, ends or its progress significantly changes.
762      * @param inputPoints  list of input points to be used to estimate an
763      *                     Euclidean 3D transformation.
764      * @param outputPoints list of output points to be used to estimate an
765      *                     Euclidean 3D transformation.
766      * @param method       method of a robust estimator algorithm to estimate the best
767      *                     Euclidean 3D transformation.
768      * @return an instance of Euclidean 3D transformation estimator.
769      * @throws IllegalArgumentException if provided lists of points don't have
770      *                                  the same size or their size is smaller than MINIMUM_SIZE.
771      */
772     public static EuclideanTransformation3DRobustEstimator create(
773             final EuclideanTransformation3DRobustEstimatorListener listener,
774             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final RobustEstimatorMethod method) {
775         return switch (method) {
776             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
777             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
778             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
779             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
780             default -> new RANSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
781         };
782     }
783 
784     /**
785      * Creates an Euclidean 3D transformation estimator based on 3D point
786      * correspondences and using provided robust estimator method.
787      *
788      * @param qualityScores quality scores corresponding to each pair of matched
789      *                      points.
790      * @param method        method of a robust estimator algorithm to estimate the best
791      *                      Euclidean 3D transformation.
792      * @return an instance of Euclidean 3D transformation estimator.
793      * @throws IllegalArgumentException if provided quality scores length is
794      *                                  smaller than MINIMUM_SIZE (i.e. 3 matched points).
795      */
796     public static EuclideanTransformation3DRobustEstimator create(
797             final double[] qualityScores, final RobustEstimatorMethod method) {
798         return switch (method) {
799             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator();
800             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator();
801             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(qualityScores);
802             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(qualityScores);
803             default -> new RANSACEuclideanTransformation3DRobustEstimator();
804         };
805     }
806 
807     /**
808      * Creates an Euclidean 3D transformation estimator based on 3D point
809      * correspondences and using provided robust estimator method.
810      *
811      * @param inputPoints   list of input points to be used to estimate an
812      *                      Euclidean 3D transformation.
813      * @param outputPoints  list of output points to be used to estimate an
814      *                      Euclidean 3D transformation.
815      * @param qualityScores quality scores corresponding to each pair of matched
816      *                      points.
817      * @param method        method of a robust estimator algorithm to estimate the best
818      *                      Euclidean 3D transformation.
819      * @return an instance of Euclidean 3D transformation estimator.
820      * @throws IllegalArgumentException if provided lists of points or scores
821      *                                  don't have the same size or their size is smaller than MINIMUM_SIZE.
822      */
823     public static EuclideanTransformation3DRobustEstimator create(
824             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores,
825             final RobustEstimatorMethod method) {
826         return switch (method) {
827             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
828             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
829             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints, qualityScores);
830             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(
831                     inputPoints, outputPoints, qualityScores);
832             default -> new RANSACEuclideanTransformation3DRobustEstimator(inputPoints, outputPoints);
833         };
834     }
835 
836     /**
837      * Creates an Euclidean 3D transformation estimator based on 3D point
838      * correspondences and using provided robust estimator method.
839      *
840      * @param listener      listener to be notified of events such as when estimation
841      *                      starts, ends or its progress significantly changes.
842      * @param qualityScores quality scores corresponding to each pair of matched
843      *                      points.
844      * @param method        method of a robust estimator algorithm to estimate the best
845      *                      Euclidean 3D transformation.
846      * @return an instance of Euclidean 3D transformation estimator.
847      * @throws IllegalArgumentException if provided quality scores don't have
848      *                                  the required minimum size.
849      */
850     public static EuclideanTransformation3DRobustEstimator create(
851             final EuclideanTransformation3DRobustEstimatorListener listener, final double[] qualityScores,
852             final RobustEstimatorMethod method) {
853         return switch (method) {
854             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(listener);
855             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(listener);
856             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(listener, qualityScores);
857             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(listener, qualityScores);
858             default -> new RANSACEuclideanTransformation3DRobustEstimator(listener);
859         };
860     }
861 
862     /**
863      * Creates an Euclidean 3D transformation estimator based on 3D point
864      * correspondences and using provided robust estimator method.
865      *
866      * @param listener      listener to be notified of events such as when estimation
867      *                      starts, ends or its progress significantly changes.
868      * @param inputPoints   list of input points to be used to estimate an
869      *                      Euclidean 3D transformation.
870      * @param outputPoints  list of output points to be used to estimate an
871      *                      Euclidean 3D transformation.
872      * @param qualityScores quality scores corresponding to each pair of matched
873      *                      points.
874      * @param method        method of a robust estimator algorithm to estimate the best
875      *                      Euclidean 3D transformation.
876      * @return an instance of Euclidean 3D transformation estimator.
877      * @throws IllegalArgumentException if provided lists of points don't have
878      *                                  the same size of their size is smaller than MINIMUM_SIZE.
879      */
880     public static EuclideanTransformation3DRobustEstimator create(
881             final EuclideanTransformation3DRobustEstimatorListener listener,
882             final List<Point3D> inputPoints, final List<Point3D> outputPoints,
883             final double[] qualityScores, final RobustEstimatorMethod method) {
884         return switch (method) {
885             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
886             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
887             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(
888                     listener, inputPoints, outputPoints, qualityScores);
889             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(
890                     listener, inputPoints, outputPoints, qualityScores);
891             default -> new RANSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints);
892         };
893     }
894 
895     /**
896      * Creates an Euclidean 3D transformation estimator based on 3D point
897      * correspondences and using provided robust estimator method.
898      *
899      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
900      * @param method                 method of a robust estimator algorithm to estimate
901      *                               the best Euclidean 3D transformation.
902      * @return an instance of Euclidean 3D transformation estimator.
903      */
904     public static EuclideanTransformation3DRobustEstimator create(
905             final boolean weakMinimumSizeAllowed, final RobustEstimatorMethod method) {
906         return switch (method) {
907             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
908             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
909             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
910             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
911             default -> new RANSACEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
912         };
913     }
914 
915     /**
916      * Creates an Euclidean 3D transformation estimator based on 3D point
917      * correspondences and using provided estimator method.
918      *
919      * @param inputPoints            list of input points to be used to estimate an
920      *                               Euclidean 3D transformation.
921      * @param outputPoints           list of output points to be used to estimate an
922      *                               Euclidean 3D transformation.
923      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
924      * @param method                 method of a robust estimator algorithm to estimate the best
925      *                               Euclidean 3D transformation.
926      * @return an instance of Euclidean 3D transformation estimator.
927      * @throws IllegalArgumentException if provided lists of points don't have
928      *                                  the same size or their size is smaller than MINIMUM_SIZE.
929      */
930     public static EuclideanTransformation3DRobustEstimator create(
931             final List<Point3D> inputPoints, final List<Point3D> outputPoints,
932             final boolean weakMinimumSizeAllowed, final RobustEstimatorMethod method) {
933         return switch (method) {
934             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(
935                     inputPoints, outputPoints, weakMinimumSizeAllowed);
936             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(
937                     inputPoints, outputPoints, weakMinimumSizeAllowed);
938             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(
939                     inputPoints, outputPoints, weakMinimumSizeAllowed);
940             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(
941                     inputPoints, outputPoints, weakMinimumSizeAllowed);
942             default -> new RANSACEuclideanTransformation3DRobustEstimator(
943                     inputPoints, outputPoints, weakMinimumSizeAllowed);
944         };
945     }
946 
947     /**
948      * Creates an Euclidean 3D transformation estimator based on 3D point
949      * correspondences and using provided robust estimator method.
950      *
951      * @param listener               listener to be notified of events such as when estimation
952      *                               starts, ends or its progress significantly changes.
953      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
954      * @param method                 method of a robust estimator algorithm to estimate the best
955      *                               Euclidean 3D transformation.
956      * @return an instance of Euclidean 3D transformation estimator.
957      */
958     public static EuclideanTransformation3DRobustEstimator create(
959             final EuclideanTransformation3DRobustEstimatorListener listener, final boolean weakMinimumSizeAllowed,
960             final RobustEstimatorMethod method) {
961         return switch (method) {
962             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
963             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
964             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
965             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
966             default -> new RANSACEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
967         };
968     }
969 
970     /**
971      * Creates an Euclidean 3D transformation estimator based on 3D point
972      * correspondences and using provided robust estimator method.
973      *
974      * @param listener               listener to be notified of events such as when estimation
975      *                               starts, ends or its progress significantly changes.
976      * @param inputPoints            list of input points to be used to estimate an
977      *                               Euclidean 3D transformation.
978      * @param outputPoints           list of output points to be used to estimate an
979      *                               Euclidean 3D transformation.
980      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
981      * @param method                 method of a robust estimator algorithm to estimate the best
982      *                               Euclidean 3D transformation.
983      * @return an instance of Euclidean 3D transformation estimator.
984      * @throws IllegalArgumentException if provided lists of points don't have
985      *                                  the same size or their size is smaller than MINIMUM_SIZE.
986      */
987     public static EuclideanTransformation3DRobustEstimator create(
988             final EuclideanTransformation3DRobustEstimatorListener listener,
989             final List<Point3D> inputPoints, final List<Point3D> outputPoints,
990             final boolean weakMinimumSizeAllowed, final RobustEstimatorMethod method) {
991         return switch (method) {
992             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints,
993                     weakMinimumSizeAllowed);
994             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints,
995                     weakMinimumSizeAllowed);
996             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints,
997                     weakMinimumSizeAllowed);
998             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints,
999                     weakMinimumSizeAllowed);
1000             default -> new RANSACEuclideanTransformation3DRobustEstimator(listener, inputPoints, outputPoints,
1001                     weakMinimumSizeAllowed);
1002         };
1003     }
1004 
1005     /**
1006      * Creates an Euclidean 3D transformation estimator based on 3D point
1007      * correspondences and using provided robust estimator method.
1008      *
1009      * @param qualityScores          quality scores corresponding to each pair of matched
1010      *                               points.
1011      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1012      * @param method                 method of a robust estimator algorithm to estimate the best
1013      *                               Euclidean 3D transformation.
1014      * @return an instance of Euclidean 3D transformation estimator.
1015      * @throws IllegalArgumentException if provided quality scores length is
1016      *                                  smaller than MINIMUM_SIZE (i.e. 3 matched points).
1017      */
1018     public static EuclideanTransformation3DRobustEstimator create(
1019             final double[] qualityScores, final boolean weakMinimumSizeAllowed, final RobustEstimatorMethod method) {
1020         return switch (method) {
1021             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
1022             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
1023             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(qualityScores, weakMinimumSizeAllowed);
1024             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(qualityScores, weakMinimumSizeAllowed);
1025             default -> new RANSACEuclideanTransformation3DRobustEstimator(weakMinimumSizeAllowed);
1026         };
1027     }
1028 
1029     /**
1030      * Creates an Euclidean 3D transformation estimator based on 3D point
1031      * correspondences and using provided robust estimator method.
1032      *
1033      * @param inputPoints            list of input points to be used to estimate an
1034      *                               Euclidean 3D transformation.
1035      * @param outputPoints           list of output points to be used to estimate an
1036      *                               Euclidean 3D transformation.
1037      * @param qualityScores          quality scores corresponding to each pair of matched
1038      *                               points.
1039      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1040      * @param method                 method of a robust estimator algorithm to estimate the best
1041      *                               Euclidean 3D transformation.
1042      * @return an instance of Euclidean 3D transformation estimator.
1043      * @throws IllegalArgumentException if provided lists of points or scores
1044      *                                  don't have the same size or their size is smaller than MINIMUM_SIZE.
1045      */
1046     public static EuclideanTransformation3DRobustEstimator create(
1047             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores,
1048             final boolean weakMinimumSizeAllowed, final RobustEstimatorMethod method) {
1049         return switch (method) {
1050             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(
1051                     inputPoints, outputPoints, weakMinimumSizeAllowed);
1052             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(
1053                     inputPoints, outputPoints, weakMinimumSizeAllowed);
1054             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(
1055                     inputPoints, outputPoints, qualityScores, weakMinimumSizeAllowed);
1056             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(
1057                     inputPoints, outputPoints, qualityScores, weakMinimumSizeAllowed);
1058             default -> new RANSACEuclideanTransformation3DRobustEstimator(
1059                     inputPoints, outputPoints, weakMinimumSizeAllowed);
1060         };
1061     }
1062 
1063     /**
1064      * Creates an Euclidean 3D transformation estimator based on 3D point
1065      * correspondences and using provided robust estimator method.
1066      *
1067      * @param listener               listener to be notified of events such as when estimation
1068      *                               starts, ends or its progress significantly changes.
1069      * @param qualityScores          quality scores corresponding to each pair of matched
1070      *                               points.
1071      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1072      * @param method                 method of a robust estimator algorithm to estimate the best
1073      *                               Euclidean 3D transformation.
1074      * @return an instance of Euclidean 3D transformation estimator.
1075      * @throws IllegalArgumentException if provided quality scores don't have
1076      *                                  the required minimum size.
1077      */
1078     public static EuclideanTransformation3DRobustEstimator create(
1079             final EuclideanTransformation3DRobustEstimatorListener listener, final double[] qualityScores,
1080             final boolean weakMinimumSizeAllowed, final RobustEstimatorMethod method) {
1081         return switch (method) {
1082             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
1083             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
1084             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(
1085                     listener, qualityScores, weakMinimumSizeAllowed);
1086             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(
1087                     listener, qualityScores, weakMinimumSizeAllowed);
1088             default -> new RANSACEuclideanTransformation3DRobustEstimator(listener, weakMinimumSizeAllowed);
1089         };
1090     }
1091 
1092     /**
1093      * Creates an Euclidean 3D transformation estimator based on 3D point
1094      * correspondences and using provided robust estimator method.
1095      *
1096      * @param listener               listener to be notified of events such as when estimation
1097      *                               starts, ends or its progress significantly changes.
1098      * @param inputPoints            list of input points to be used to estimate an
1099      *                               Euclidean 3D transformation.
1100      * @param outputPoints           list of output points to be used to estimate an
1101      *                               Euclidean 3D transformation.
1102      * @param qualityScores          quality scores corresponding to each pair of matched
1103      *                               points.
1104      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1105      * @param method                 method of a robust estimator algorithm to estimate the best
1106      *                               Euclidean 3D transformation.
1107      * @return an instance of Euclidean 3D transformation estimator.
1108      * @throws IllegalArgumentException if provided lists of points don't have
1109      *                                  the same size of their size is smaller than MINIMUM_SIZE.
1110      */
1111     public static EuclideanTransformation3DRobustEstimator create(
1112             final EuclideanTransformation3DRobustEstimatorListener listener,
1113             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores,
1114             final boolean weakMinimumSizeAllowed, final RobustEstimatorMethod method) {
1115         return switch (method) {
1116             case LMEDS -> new LMedSEuclideanTransformation3DRobustEstimator(
1117                     listener, inputPoints, outputPoints, weakMinimumSizeAllowed);
1118             case MSAC -> new MSACEuclideanTransformation3DRobustEstimator(
1119                     listener, inputPoints, outputPoints, weakMinimumSizeAllowed);
1120             case PROSAC -> new PROSACEuclideanTransformation3DRobustEstimator(
1121                     listener, inputPoints, outputPoints, qualityScores, weakMinimumSizeAllowed);
1122             case PROMEDS -> new PROMedSEuclideanTransformation3DRobustEstimator(
1123                     listener, inputPoints, outputPoints, qualityScores, weakMinimumSizeAllowed);
1124             default -> new RANSACEuclideanTransformation3DRobustEstimator(
1125                     listener, inputPoints, outputPoints, weakMinimumSizeAllowed);
1126         };
1127     }
1128 
1129     /**
1130      * Creates an Euclidean 3D transformation estimator based on 3D point
1131      * correspondences and using default robust estimator method.
1132      *
1133      * @return an instance of Euclidean 3D transformation estimator.
1134      */
1135     public static EuclideanTransformation3DRobustEstimator create() {
1136         return create(DEFAULT_ROBUST_METHOD);
1137     }
1138 
1139     /**
1140      * Creates an Euclidean 3D transformation estimator based on 3D point
1141      * correspondences and using default robust estimator method.
1142      *
1143      * @param inputPoints  list of input points to be used to estimate an
1144      *                     Euclidean 3D transformation.
1145      * @param outputPoints list of output points to be used to estimate an
1146      *                     Euclidean 3D transformation.
1147      * @return an instance of Euclidean 3D transformation estimator.
1148      * @throws IllegalArgumentException if provided lists of points don't have
1149      *                                  the same size of their size is smaller than MINIMUM_SIZE.
1150      */
1151     public static EuclideanTransformation3DRobustEstimator create(
1152             final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
1153         return create(inputPoints, outputPoints, DEFAULT_ROBUST_METHOD);
1154     }
1155 
1156     /**
1157      * Creates an Euclidean 3D transformation estimator based on 3D point
1158      * correspondences and using default robust estimator method.
1159      *
1160      * @param listener listener to be notified of events such as when estimation
1161      *                 starts, ends or its progress significantly changes.
1162      * @return an instance of Euclidean 3D transformation estimator.
1163      */
1164     public static EuclideanTransformation3DRobustEstimator create(
1165             final EuclideanTransformation3DRobustEstimatorListener listener) {
1166         return create(listener, DEFAULT_ROBUST_METHOD);
1167     }
1168 
1169     /**
1170      * Creates an Euclidean 3D transformation estimator based on 3D point
1171      * correspondences and using default robust estimator method.
1172      *
1173      * @param listener     listener to be notified of events such as when estimation
1174      *                     starts, ends or its progress significantly changes.
1175      * @param inputPoints  list of input points to be used to estimate an
1176      *                     Euclidean 3D transformation.
1177      * @param outputPoints list of output points to be used to estimate an
1178      *                     Euclidean 3D transformation.
1179      * @return an instance of Euclidean 3D transformation estimator.
1180      * @throws IllegalArgumentException if provided lists of points don't have
1181      *                                  the same size or their size is smaller than MINIMUM_SIZE.
1182      */
1183     public static EuclideanTransformation3DRobustEstimator create(
1184             final EuclideanTransformation3DRobustEstimatorListener listener,
1185             final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
1186         return create(listener, inputPoints, outputPoints, DEFAULT_ROBUST_METHOD);
1187     }
1188 
1189     /**
1190      * Creates an Euclidean 3D transformation estimator based on 3D point
1191      * correspondences and using default robust estimator method.
1192      *
1193      * @param qualityScores quality scores corresponding to each pair of matched
1194      *                      points.
1195      * @return an instance of Euclidean 3D transformation estimator.
1196      */
1197     public static EuclideanTransformation3DRobustEstimator create(final double[] qualityScores) {
1198         return create(qualityScores, DEFAULT_ROBUST_METHOD);
1199     }
1200 
1201     /**
1202      * Creates an Euclidean 3D transformation estimator based on 3D point
1203      * correspondences and using default robust estimator method.
1204      *
1205      * @param inputPoints   list of input points to be used to estimate an
1206      *                      Euclidean 3D transformation.
1207      * @param outputPoints  list of output points ot be used to estimate an
1208      *                      Euclidean 3D transformation.
1209      * @param qualityScores quality scores corresponding to each pair of points.
1210      * @return an instance of Euclidean 3D transformation estimator.
1211      * @throws IllegalArgumentException if provided lists of points don't have
1212      *                                  the same size or their size is smaller than MINIMUM_SIZE.
1213      */
1214     public static EuclideanTransformation3DRobustEstimator create(
1215             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores) {
1216         return create(inputPoints, outputPoints, qualityScores, DEFAULT_ROBUST_METHOD);
1217     }
1218 
1219     /**
1220      * Creates an Euclidean 3D transformation estimator based on 3D point
1221      * correspondences and using default robust estimator method.
1222      *
1223      * @param listener      listener to be notified of events such as when estimation
1224      *                      starts, ends or its progress significantly changes.
1225      * @param qualityScores quality scores corresponding to each pair of matched
1226      *                      points.
1227      * @return an instance of Euclidean 3D transformation estimator.
1228      */
1229     public static EuclideanTransformation3DRobustEstimator create(
1230             final EuclideanTransformation3DRobustEstimatorListener listener, final double[] qualityScores) {
1231         return create(listener, qualityScores, DEFAULT_ROBUST_METHOD);
1232     }
1233 
1234     /**
1235      * Creates an Euclidean 3D transformation estimator based on 3D point
1236      * correspondences and using default robust estimator method.
1237      *
1238      * @param listener      listener to be notified of events such as when estimation
1239      *                      starts, ends or its progress significantly changes.
1240      * @param inputPoints   list of input points to be used to estimate an
1241      *                      Euclidean 3D transformation.
1242      * @param outputPoints  list of output points ot be used to estimate an
1243      *                      Euclidean 3D transformation.
1244      * @param qualityScores quality scores corresponding to each pair of matched
1245      *                      points.
1246      * @return an instance of Euclidean 3D transformation estimator.
1247      * @throws IllegalArgumentException if provided lists of points don't have
1248      *                                  the same size or their size is smaller than MINIMUM_SIZE.
1249      */
1250     public static EuclideanTransformation3DRobustEstimator create(
1251             final EuclideanTransformation3DRobustEstimatorListener listener,
1252             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores) {
1253         return create(listener, inputPoints, outputPoints, qualityScores, DEFAULT_ROBUST_METHOD);
1254     }
1255 
1256     /**
1257      * Creates an Euclidean 3D transformation estimator based on 3D point
1258      * correspondences and using default robust estimator method.
1259      *
1260      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1261      * @return an instance of Euclidean 3D transformation estimator.
1262      */
1263     public static EuclideanTransformation3DRobustEstimator create(final boolean weakMinimumSizeAllowed) {
1264         return create(weakMinimumSizeAllowed, DEFAULT_ROBUST_METHOD);
1265     }
1266 
1267     /**
1268      * Creates an Euclidean 3D transformation estimator based on 3D point
1269      * correspondences and using default robust estimator method.
1270      *
1271      * @param inputPoints            list of input points to be used to estimate an
1272      *                               Euclidean 3D transformation.
1273      * @param outputPoints           list of output points to be used to estimate an
1274      *                               Euclidean 3D transformation.
1275      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1276      * @return an instance of Euclidean 3D transformation estimator.
1277      * @throws IllegalArgumentException if provided lists of points don't have
1278      *                                  the same size of their size is smaller than MINIMUM_SIZE.
1279      */
1280     public static EuclideanTransformation3DRobustEstimator create(
1281             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final boolean weakMinimumSizeAllowed) {
1282         return create(inputPoints, outputPoints, weakMinimumSizeAllowed, DEFAULT_ROBUST_METHOD);
1283     }
1284 
1285     /**
1286      * Creates an Euclidean 3D transformation estimator based on 3D point
1287      * correspondences and using default robust estimator method.
1288      *
1289      * @param listener               listener to be notified of events such as when estimation
1290      *                               starts, ends or its progress significantly changes.
1291      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1292      * @return an instance of Euclidean 3D transformation estimator.
1293      */
1294     public static EuclideanTransformation3DRobustEstimator create(
1295             final EuclideanTransformation3DRobustEstimatorListener listener, final boolean weakMinimumSizeAllowed) {
1296         return create(listener, weakMinimumSizeAllowed, DEFAULT_ROBUST_METHOD);
1297     }
1298 
1299     /**
1300      * Creates an Euclidean 3D transformation estimator based on 3D point
1301      * correspondences and using default robust estimator method.
1302      *
1303      * @param listener               listener to be notified of events such as when estimation
1304      *                               starts, ends or its progress significantly changes.
1305      * @param inputPoints            list of input points to be used to estimate an
1306      *                               Euclidean 3D transformation.
1307      * @param outputPoints           list of output points to be used to estimate an
1308      *                               Euclidean 3D transformation.
1309      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1310      * @return an instance of Euclidean 3D transformation estimator.
1311      * @throws IllegalArgumentException if provided lists of points don't have
1312      *                                  the same size or their size is smaller than MINIMUM_SIZE.
1313      */
1314     public static EuclideanTransformation3DRobustEstimator create(
1315             final EuclideanTransformation3DRobustEstimatorListener listener,
1316             final List<Point3D> inputPoints, final List<Point3D> outputPoints, final boolean weakMinimumSizeAllowed) {
1317         return create(listener, inputPoints, outputPoints, weakMinimumSizeAllowed, DEFAULT_ROBUST_METHOD);
1318     }
1319 
1320     /**
1321      * Creates an Euclidean 3D transformation estimator based on 3D point
1322      * correspondences and using default robust estimator method.
1323      *
1324      * @param qualityScores          quality scores corresponding to each pair of matched
1325      *                               points.
1326      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1327      * @return an instance of Euclidean 3D transformation estimator.
1328      */
1329     public static EuclideanTransformation3DRobustEstimator create(
1330             final double[] qualityScores, final boolean weakMinimumSizeAllowed) {
1331         return create(qualityScores, weakMinimumSizeAllowed, DEFAULT_ROBUST_METHOD);
1332     }
1333 
1334     /**
1335      * Creates an Euclidean 3D transformation estimator based on 3D point
1336      * correspondences and using default robust estimator method.
1337      *
1338      * @param inputPoints            list of input points to be used to estimate an
1339      *                               Euclidean 3D transformation.
1340      * @param outputPoints           list of output points ot be used to estimate an
1341      *                               Euclidean 3D transformation.
1342      * @param qualityScores          quality scores corresponding to each pair of points.
1343      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1344      * @return an instance of Euclidean 3D transformation estimator.
1345      * @throws IllegalArgumentException if provided lists of points don't have
1346      *                                  the same size or their size is smaller than MINIMUM_SIZE.
1347      */
1348     public static EuclideanTransformation3DRobustEstimator create(
1349             final List<Point3D> inputPoints, final List<Point3D> outputPoints,
1350             final double[] qualityScores, final boolean weakMinimumSizeAllowed) {
1351         return create(inputPoints, outputPoints, qualityScores, weakMinimumSizeAllowed, DEFAULT_ROBUST_METHOD);
1352     }
1353 
1354     /**
1355      * Creates an Euclidean 3D transformation estimator based on 3D point
1356      * correspondences and using default robust estimator method.
1357      *
1358      * @param listener               listener to be notified of events such as when estimation
1359      *                               starts, ends or its progress significantly changes.
1360      * @param qualityScores          quality scores corresponding to each pair of matched
1361      *                               points.
1362      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1363      * @return an instance of Euclidean 3D transformation estimator.
1364      */
1365     public static EuclideanTransformation3DRobustEstimator create(
1366             final EuclideanTransformation3DRobustEstimatorListener listener,
1367             final double[] qualityScores, final boolean weakMinimumSizeAllowed) {
1368         return create(listener, qualityScores, weakMinimumSizeAllowed, DEFAULT_ROBUST_METHOD);
1369     }
1370 
1371     /**
1372      * Creates an Euclidean 3D transformation estimator based on 3D point
1373      * correspondences and using default robust estimator method.
1374      *
1375      * @param listener               listener to be notified of events such as when estimation
1376      *                               starts, ends or its progress significantly changes.
1377      * @param inputPoints            list of input points to be used to estimate an
1378      *                               Euclidean 3D transformation.
1379      * @param outputPoints           list of output points ot be used to estimate an
1380      *                               Euclidean 3D transformation.
1381      * @param qualityScores          quality scores corresponding to each pair of matched
1382      *                               points.
1383      * @param weakMinimumSizeAllowed true allows 3 points, false requires 4.
1384      * @return an instance of Euclidean 3D transformation estimator.
1385      * @throws IllegalArgumentException if provided lists of points don't have
1386      *                                  the same size or their size is smaller than MINIMUM_SIZE.
1387      */
1388     public static EuclideanTransformation3DRobustEstimator create(
1389             final EuclideanTransformation3DRobustEstimatorListener listener,
1390             final List<Point3D> inputPoints, final List<Point3D> outputPoints,
1391             final double[] qualityScores, final boolean weakMinimumSizeAllowed) {
1392         return create(listener, inputPoints, outputPoints, qualityScores, weakMinimumSizeAllowed,
1393                 DEFAULT_ROBUST_METHOD);
1394     }
1395 
1396 
1397     /**
1398      * Internal method to set lists of points to be used to estimate an
1399      * Euclidean 3D transformation.
1400      * This method does not check whether estimator is locked or not.
1401      *
1402      * @param inputPoints  list of input points to be used to estimate an
1403      *                     Euclidean 3D transformation.
1404      * @param outputPoints list of output points to be used to estimate an
1405      *                     Euclidean 3D transformation.
1406      * @throws IllegalArgumentException if provided lists of points don't have
1407      *                                  the same size or their size is smaller than MINIMUM_SIZE.
1408      */
1409     private void internalSetPoints(final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
1410         if (inputPoints.size() < getMinimumPoints()) {
1411             throw new IllegalArgumentException();
1412         }
1413         if (inputPoints.size() != outputPoints.size()) {
1414             throw new IllegalArgumentException();
1415         }
1416         this.inputPoints = inputPoints;
1417         this.outputPoints = outputPoints;
1418     }
1419 
1420     /**
1421      * Attempts to refine provided solution if refinement is requested.
1422      * This method returns a refined solution of the same provided solution
1423      * if refinement is not requested or has failed.
1424      * If refinement is enabled, and it is requested to keep covariance, this
1425      * method will also keep covariance of refined transformation.
1426      *
1427      * @param transformation transformation estimated by a robust estimator
1428      *                       without refinement.
1429      * @return solution after refinement (if requested) or the provided
1430      * non-refined solution if not requested or refinement failed.
1431      */
1432     protected EuclideanTransformation3D attemptRefine(final EuclideanTransformation3D transformation) {
1433         if (refineResult) {
1434             final var refiner = new EuclideanTransformation3DRefiner(transformation, keepCovariance, getInliersData(),
1435                     inputPoints, outputPoints, getRefinementStandardDeviation());
1436 
1437             try {
1438                 final var result = new EuclideanTransformation3D();
1439                 final var improved = refiner.refine(result);
1440 
1441                 if (keepCovariance) {
1442                     // keep covariance
1443                     covariance = refiner.getCovariance();
1444                 }
1445 
1446                 return improved ? result : transformation;
1447             } catch (final Exception e) {
1448                 // refinement failed, so we return input value
1449                 return transformation;
1450             }
1451         } else {
1452             return transformation;
1453         }
1454     }
1455 
1456     /**
1457      * Gets standard deviation used for Levenberg-Marquardt fitting during
1458      * refinement.
1459      * Returned value gives an indication of how much variance each residual
1460      * has.
1461      * Typically, this value is related to the threshold used on each robust
1462      * estimation, since residuals of found inliers are within the range of
1463      * such threshold.
1464      *
1465      * @return standard deviation used for refinement.
1466      */
1467     protected abstract double getRefinementStandardDeviation();
1468 }