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.Plane;
19 import com.irurueta.geometry.Point3D;
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 3D plane
27 * that passes through a collection of 3D 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 PlaneRobustEstimator {
33 /**
34 * Minimum number of 3D points required to estimate a plane.
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 PlaneRobustEstimatorListener 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 3D plane. Provided list must have
121 * a size greater or equal than MINIMUM_SIZE.
122 */
123 protected List<Point3D> points;
124
125 /**
126 * Constructor.
127 */
128 protected PlaneRobustEstimator() {
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 PlaneRobustEstimator(final PlaneRobustEstimatorListener 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 3D points to estimate a 3D plane.
151 * @throws IllegalArgumentException if provided list of points doesn't have
152 * a size greater or equal than MINIMUM_SIZE.
153 */
154 protected PlaneRobustEstimator(final List<Point3D> 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 3D points to estimate a 3D plane.
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 doesn't have
168 * a size greater or equal than MINIMUM_SIZE.
169 */
170 protected PlaneRobustEstimator(final PlaneRobustEstimatorListener listener, final List<Point3D> 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 PlaneRobustEstimatorListener 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 PlaneRobustEstimatorListener 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 3D plane.
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 3D plane.
324 */
325 public List<Point3D> getPoints() {
326 return points;
327 }
328
329 /**
330 * Sets list of points to be used to estimate a 3D plane.
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 3D plane.
334 * @throws IllegalArgumentException if provided list of points doesn'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<Point3D> 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 3D plane estimation.
348 * This is true when a minimum of 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 measure.
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. 2 samples).
379 */
380 public void setQualityScores(final double[] qualityScores) throws LockedException {
381 }
382
383 /**
384 * Creates a 3D plane robust estimator based on 3D point samples and using
385 * provided robust estimator method.
386 *
387 * @param method method of a robust estimator algorithm to estimate the best
388 * 3D plane.
389 * @return an instance of a 3D plane robust estimator.
390 */
391 public static PlaneRobustEstimator create(final RobustEstimatorMethod method) {
392 return switch (method) {
393 case LMEDS -> new LMedSPlaneRobustEstimator();
394 case MSAC -> new MSACPlaneRobustEstimator();
395 case PROSAC -> new PROSACPlaneRobustEstimator();
396 case PROMEDS -> new PROMedSPlaneRobustEstimator();
397 default -> new RANSACPlaneRobustEstimator();
398 };
399 }
400
401 /**
402 * Creates a 3D plane robust estimator based on 3D point samples and using
403 * provided points and robust estimator method.
404 *
405 * @param points 3D points to estimate a 3D plane.
406 * @param method method of a robust estimator algorithm to estimate the best
407 * 3D plane.
408 * @return an instance of a 3D plane robust estimator.
409 * @throws IllegalArgumentException if provided list of points doesn't have
410 * a size greater or equal than MINIMUM_SIZE.
411 */
412 public static PlaneRobustEstimator create(final List<Point3D> points, final RobustEstimatorMethod method) {
413 return switch (method) {
414 case LMEDS -> new LMedSPlaneRobustEstimator(points);
415 case MSAC -> new MSACPlaneRobustEstimator(points);
416 case PROSAC -> new PROSACPlaneRobustEstimator(points);
417 case PROMEDS -> new PROMedSPlaneRobustEstimator(points);
418 default -> new RANSACPlaneRobustEstimator(points);
419 };
420 }
421
422 /**
423 * Creates a 3D plane robust estimator based on 3D point samples and using
424 * provided listener.
425 *
426 * @param listener listener to be notified of events such as when estimation
427 * starts, ends or its progress significantly changes.
428 * @param method method of a robust estimator algorithm to estimate the best
429 * 3D plane.
430 * @return an instance of a 3D plane robust estimator.
431 */
432 public static PlaneRobustEstimator create(
433 final PlaneRobustEstimatorListener listener, final RobustEstimatorMethod method) {
434 return switch (method) {
435 case LMEDS -> new LMedSPlaneRobustEstimator(listener);
436 case MSAC -> new MSACPlaneRobustEstimator(listener);
437 case PROSAC -> new PROSACPlaneRobustEstimator(listener);
438 case PROMEDS -> new PROMedSPlaneRobustEstimator(listener);
439 default -> new RANSACPlaneRobustEstimator(listener);
440 };
441 }
442
443 /**
444 * Creates a 3D plane robust estimator based on 3D point samples and using
445 * provided listener and points.
446 *
447 * @param listener listener to be notified of events such as when estimation
448 * starts, ends or its progress significantly changes.
449 * @param points 3D points to estimate a 3D plane.
450 * @param method method of a robust estimator algorithm to estimate the best
451 * 3D plane.
452 * @return an instance of a 3D plane robust estimator.
453 * @throws IllegalArgumentException if provided list of points doesn't have
454 * a size greater or equal than MINIMUM_SIZE.
455 */
456 public static PlaneRobustEstimator create(
457 final PlaneRobustEstimatorListener listener, final List<Point3D> points,
458 final RobustEstimatorMethod method) {
459 return switch (method) {
460 case LMEDS -> new LMedSPlaneRobustEstimator(listener, points);
461 case MSAC -> new MSACPlaneRobustEstimator(listener, points);
462 case PROSAC -> new PROSACPlaneRobustEstimator(listener, points);
463 case PROMEDS -> new PROMedSPlaneRobustEstimator(listener, points);
464 default -> new RANSACPlaneRobustEstimator(listener, points);
465 };
466 }
467
468 /**
469 * Creates a 3D plane robust estimator based on 3D point samples and using
470 * provided robust estimator method.
471 *
472 * @param qualityScores quality scores corresponding to each provided point.
473 * @param method method of a robust estimator algorithm to estimate the best
474 * 3D plane.
475 * @return an instance of a 3D plane robust estimator.
476 * @throws IllegalArgumentException if provided quality scores length is
477 * smaller than MINIMUM_SIZE (i.e. 3 points).
478 */
479 public static PlaneRobustEstimator create(final double[] qualityScores, final RobustEstimatorMethod method) {
480 return switch (method) {
481 case LMEDS -> new LMedSPlaneRobustEstimator();
482 case MSAC -> new MSACPlaneRobustEstimator();
483 case PROSAC -> new PROSACPlaneRobustEstimator(qualityScores);
484 case PROMEDS -> new PROMedSPlaneRobustEstimator(qualityScores);
485 default -> new RANSACPlaneRobustEstimator();
486 };
487 }
488
489 /**
490 * Creates a 3D plane robust estimator based on 3D point samples and using
491 * provided points and robust estimator method.
492 *
493 * @param points 3D points to estimate a 3D plane.
494 * @param qualityScores quality scores corresponding to each provided point.
495 * @param method method of a robust estimator algorithm to estimate the best
496 * 3D plane.
497 * @return an instance of a 3D plane robust estimator.
498 * @throws IllegalArgumentException if provided list of points doesn't have
499 * the same size as the list of provided quality scores, or it their size
500 * is not greater or equal than MINIMUM_SIZE.
501 */
502 public static PlaneRobustEstimator create(
503 final List<Point3D> points, final double[] qualityScores, final RobustEstimatorMethod method) {
504 return switch (method) {
505 case LMEDS -> new LMedSPlaneRobustEstimator(points);
506 case MSAC -> new MSACPlaneRobustEstimator(points);
507 case PROSAC -> new PROSACPlaneRobustEstimator(points, qualityScores);
508 case PROMEDS -> new PROMedSPlaneRobustEstimator(points, qualityScores);
509 default -> new RANSACPlaneRobustEstimator(points);
510 };
511 }
512
513 /**
514 * Creates a 3D plane robust estimator based on 3D point samples and using
515 * provided listener.
516 *
517 * @param listener listener to be notified of events such as when estimation
518 * starts, ends or its progress significantly changes.
519 * @param qualityScores quality scores corresponding to each provided point.
520 * @param method method of a robust estimator algorithm to estimate the best
521 * 3D plane.
522 * @return an instance of a 3D plane robust estimator.
523 * @throws IllegalArgumentException if provided quality scores length is
524 * smaller than MINIMUM_SIZE (i.e. 3 points).
525 */
526 public static PlaneRobustEstimator create(
527 final PlaneRobustEstimatorListener listener, final double[] qualityScores,
528 final RobustEstimatorMethod method) {
529 return switch (method) {
530 case LMEDS -> new LMedSPlaneRobustEstimator(listener);
531 case MSAC -> new MSACPlaneRobustEstimator(listener);
532 case PROSAC -> new PROSACPlaneRobustEstimator(listener, qualityScores);
533 case PROMEDS -> new PROMedSPlaneRobustEstimator(listener, qualityScores);
534 default -> new RANSACPlaneRobustEstimator(listener);
535 };
536 }
537
538 /**
539 * Creates a 3D plane robust estimator based on 3D point samples and using
540 * provided listener and points.
541 *
542 * @param listener listener to be notified of events such as when estimation
543 * starts, ends or its progress significantly changes.
544 * @param points 3D points to estimate a 3D plane.
545 * @param qualityScores quality scores corresponding to each provided point.
546 * @param method method of a robust estimator algorithm to estimate the best
547 * 3D plane.
548 * @return an instance of a 3D plane robust estimator.
549 * @throws IllegalArgumentException if provided list of points doesn't have
550 * the same size as the list of provided quality scores, or it their size
551 * is not greater or equal than MINIMUM_SIZE.
552 */
553 public static PlaneRobustEstimator create(
554 final PlaneRobustEstimatorListener listener, final List<Point3D> points, final double[] qualityScores,
555 final RobustEstimatorMethod method) {
556 return switch (method) {
557 case LMEDS -> new LMedSPlaneRobustEstimator(listener, points);
558 case MSAC -> new MSACPlaneRobustEstimator(listener, points);
559 case PROSAC -> new PROSACPlaneRobustEstimator(listener, points, qualityScores);
560 case PROMEDS -> new PROMedSPlaneRobustEstimator(listener, points, qualityScores);
561 default -> new RANSACPlaneRobustEstimator(listener, points);
562 };
563 }
564
565 /**
566 * Creates a 3D line robust estimator based on 3D point samples and using
567 * default robust estimator method.
568 *
569 * @return an instance of a 3D line robust estimator.
570 */
571 public static PlaneRobustEstimator create() {
572 return create(DEFAULT_ROBUST_METHOD);
573 }
574
575 /**
576 * Creates a 3D plane robust estimator based on 3D point samples and using
577 * provided points and default robust estimator method.
578 *
579 * @param points 3D points to estimate a 3D plane.
580 * @return an instance of a 3D plane robust estimator.
581 * @throws IllegalArgumentException if provided list of points doesn't have
582 * a size greater or equal than MINIMUM_SIZE.
583 */
584 public static PlaneRobustEstimator create(final List<Point3D> points) {
585 return create(points, DEFAULT_ROBUST_METHOD);
586 }
587
588 /**
589 * Creates a 3D plane robust estimator based on 3D point samples and using
590 * provided listener and default robust estimator method.
591 *
592 * @param listener listener to be notified of events such as when estimation
593 * starts, ends or its progress significantly changes.
594 * @return an instance of a 3D plane robust estimator.
595 */
596 public static PlaneRobustEstimator create(final PlaneRobustEstimatorListener listener) {
597 return create(listener, DEFAULT_ROBUST_METHOD);
598 }
599
600 /**
601 * Creates a 3D plane robust estimator based on 3D point samples and using
602 * provided listener and lines and default robust estimator method.
603 *
604 * @param listener listener to be notified of events such as when estimation
605 * starts, ends or its progress significantly changes.
606 * @param points 3D points to estimate a plane.
607 * @return an instance of a 3D plane robust estimator.
608 * @throws IllegalArgumentException if provided list of points doesn't have
609 * a size greater or equal than MINIMUM_SIZE.
610 */
611 public static PlaneRobustEstimator create(final PlaneRobustEstimatorListener listener, final List<Point3D> points) {
612 return create(listener, points, DEFAULT_ROBUST_METHOD);
613 }
614
615 /**
616 * Creates a 3D plane robust estimator based on 3D point samples and using
617 * default robust estimator method.
618 *
619 * @param qualityScores quality scores corresponding to each provided point
620 * @return an instance of a 3D point robust estimator.
621 * @throws IllegalArgumentException if provided quality scores length is
622 * smaller than MINIMUM_SIZE (i.e. 3 points).
623 */
624 public static PlaneRobustEstimator create(final double[] qualityScores) {
625 return create(qualityScores, DEFAULT_ROBUST_METHOD);
626 }
627
628 /**
629 * Creates a 3D plane robust estimator based on 3D point samples and using
630 * provided points and default estimator method.
631 *
632 * @param points 3D points to estimate a 3D plane.
633 * @param qualityScores quality scores corresponding to each provided point.
634 * @return an instance of a 3D plane robust estimator.
635 * @throws IllegalArgumentException if provided list of points don't have
636 * the same size as the list of provided quality scores, or if their size
637 * is not greater or equal than MINIMUM_SIZE.
638 */
639 public static PlaneRobustEstimator create(final List<Point3D> points, final double[] qualityScores) {
640 return create(points, qualityScores, DEFAULT_ROBUST_METHOD);
641 }
642
643 /**
644 * Creates a 3D plane robust estimator based on 3D point samples and using
645 * provided listener and default estimator method.
646 *
647 * @param listener listener to be notified of events such as when estimation
648 * starts, ends or its progress significantly changes.
649 * @param qualityScores quality scores corresponding to each provided point
650 * @return an instance of a circle robust estimator.
651 * @throws IllegalArgumentException if provided quality scores length is
652 * smaller than MINIMUM_SIZE (i.e. 3 points).
653 */
654 public static PlaneRobustEstimator create(
655 final PlaneRobustEstimatorListener listener, final double[] qualityScores) {
656 return create(listener, qualityScores, DEFAULT_ROBUST_METHOD);
657 }
658
659 /**
660 * Creates a 3D plane robust estimator based on 3D point samples and using
661 * provided listener and points and default estimator method.
662 *
663 * @param listener listener to be notified of events such as when estimation
664 * starts, ends or its progress significantly changes.
665 * @param points 3D points to estimate a 3D plane.
666 * @param qualityScores quality scores corresponding to each provided point
667 * @return an instance of a 3D plane robust estimator.
668 * @throws IllegalArgumentException if provided list of points don't have
669 * the same size as the list of provided quality scores, or if their size
670 * is not greater or equal than MINIMUM_SIZE.
671 */
672 public static PlaneRobustEstimator create(
673 final PlaneRobustEstimatorListener listener, final List<Point3D> points, final double[] qualityScores) {
674 return create(listener, points, qualityScores, DEFAULT_ROBUST_METHOD);
675 }
676
677 /**
678 * Estimates a 3D plane using a robust estimator and the best set of 3D
679 * points that pass through the estimated 3D plane (i.e. belong to its
680 * locus).
681 *
682 * @return a 3D plane.
683 * @throws LockedException if robust estimator is locked because an
684 * estimation is already in progress.
685 * @throws NotReadyException if provided input data is not enough to start
686 * the estimation.
687 * @throws RobustEstimatorException if estimation fails for any reason
688 * (i.e. numerical instability, no solution available, etc).
689 */
690 public abstract Plane estimate() throws LockedException, NotReadyException, RobustEstimatorException;
691
692 /**
693 * Returns method being used for robust estimation.
694 *
695 * @return method being used for robust estimation.
696 */
697 public abstract RobustEstimatorMethod getMethod();
698
699 /**
700 * Internal method to set list of 3D points to be used to estimate a 3D
701 * plane.
702 * This method does not check whether estimator is locked or not.
703 *
704 * @param points list of points to be used to estimate a 3D plane.
705 * @throws IllegalArgumentException if provided list of points doesn't have
706 * a size greater or equal than MINIMUM_SIZE.
707 */
708 private void internalSetPoints(final List<Point3D> points) {
709 if (points.size() < MINIMUM_SIZE) {
710 throw new IllegalArgumentException();
711 }
712 this.points = points;
713 }
714
715 /**
716 * Computes the residual between a 3D point and a plane.
717 *
718 * @param plane a 3D plane.
719 * @param point a 3D point.
720 * @return residual.
721 */
722 protected double residual(final Plane plane, final Point3D point) {
723 plane.normalize();
724 point.normalize();
725
726 return Math.abs(plane.signedDistance(point));
727 }
728 }