View Javadoc
1   /*
2    * Copyright (C) 2018 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.navigation.indoor.radiosource;
17  
18  import com.irurueta.geometry.Point2D;
19  import com.irurueta.navigation.LockedException;
20  import com.irurueta.navigation.NavigationException;
21  import com.irurueta.navigation.indoor.Beacon;
22  import com.irurueta.navigation.indoor.BeaconLocated2D;
23  import com.irurueta.navigation.indoor.RadioSource;
24  import com.irurueta.navigation.indoor.RadioSourceLocated;
25  import com.irurueta.navigation.indoor.RangingReadingLocated;
26  import com.irurueta.navigation.indoor.WifiAccessPoint;
27  import com.irurueta.navigation.indoor.WifiAccessPointLocated2D;
28  import com.irurueta.numerical.robust.RobustEstimatorMethod;
29  
30  import java.util.ArrayList;
31  import java.util.List;
32  
33  /**
34   * This is an abstract class to robustly estimate 2D position of a radio source (e.g. Wi-Fi
35   * access point or bluetooth beacon), by discarding outliers.
36   *
37   * @param <S> a {@link RadioSource} type.
38   */
39  @SuppressWarnings("DuplicatedCode")
40  public abstract class RobustRangingRadioSourceEstimator2D<S extends RadioSource> extends
41          RobustRangingRadioSourceEstimator<S, Point2D> {
42  
43      /**
44       * Radio source estimator used internally.
45       */
46      protected final RangingRadioSourceEstimator2D<S> innerEstimator = new RangingRadioSourceEstimator2D<>();
47  
48      /**
49       * Subset of readings used by inner estimator.
50       */
51      private final List<RangingReadingLocated<S, Point2D>> innerReadings = new ArrayList<>();
52  
53      /**
54       * Constructor.
55       */
56      protected RobustRangingRadioSourceEstimator2D() {
57          super();
58          preliminarySubsetSize = getMinReadings();
59      }
60  
61      /**
62       * Constructor.
63       * Sets radio signal ranging readings belonging to the same radio source.
64       *
65       * @param readings radio signal ranging readings belonging to the same
66       *                 radio source.
67       * @throws IllegalArgumentException if readings are not valid.
68       */
69      protected RobustRangingRadioSourceEstimator2D(final List<? extends RangingReadingLocated<S, Point2D>> readings) {
70          super(readings);
71          preliminarySubsetSize = getMinReadings();
72      }
73  
74      /**
75       * Constructor.
76       *
77       * @param listener listener in charge of attending events raised by this instance.
78       */
79      protected RobustRangingRadioSourceEstimator2D(
80              final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener) {
81          super(listener);
82          preliminarySubsetSize = getMinReadings();
83      }
84  
85      /**
86       * Constructor.
87       * Sets radio signal readings belonging to the same radio source.
88       *
89       * @param readings radio signal readings belonging to the same radio source.
90       * @param listener listener in charge of attending events raised by this instance.
91       * @throws IllegalArgumentException if readings are not valid.
92       */
93      protected RobustRangingRadioSourceEstimator2D(
94              final List<? extends RangingReadingLocated<S, Point2D>> readings,
95              final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener) {
96          super(readings, listener);
97          preliminarySubsetSize = getMinReadings();
98      }
99  
100     /**
101      * Constructor.
102      *
103      * @param initialPosition initial position to start the estimation or radio
104      *                        source position.
105      */
106     protected RobustRangingRadioSourceEstimator2D(final Point2D initialPosition) {
107         super(initialPosition);
108         preliminarySubsetSize = getMinReadings();
109     }
110 
111     /**
112      * Constructor.
113      * Sets radio signal readings belonging to the same radio source.
114      *
115      * @param readings        radio signal readings belonging to the same radio source.
116      * @param initialPosition initial position to start the estimation of radio
117      *                        source position.
118      * @throws IllegalArgumentException if readings are not valid.
119      */
120     protected RobustRangingRadioSourceEstimator2D(
121             final List<? extends RangingReadingLocated<S, Point2D>> readings, final Point2D initialPosition) {
122         super(readings, initialPosition);
123         preliminarySubsetSize = getMinReadings();
124     }
125 
126     /**
127      * Constructor.
128      *
129      * @param initialPosition initial position to start the estimation of radio
130      *                        source position.
131      * @param listener        listener in charge of attending events raised by this instance.
132      */
133     protected RobustRangingRadioSourceEstimator2D(
134             final Point2D initialPosition, final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener) {
135         super(initialPosition, listener);
136         preliminarySubsetSize = getMinReadings();
137     }
138 
139     /**
140      * Constructor.
141      * Sets radio signal ranging readings belonging to the same radio source.
142      *
143      * @param readings        radio signal ranging readings belonging to the same radio source.
144      * @param initialPosition initial position to start the estimation of radio source
145      *                        position.
146      * @param listener        listener in charge of attending events raised by this instance.
147      * @throws IllegalArgumentException if readings are not valid.
148      */
149     protected RobustRangingRadioSourceEstimator2D(
150             final List<? extends RangingReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
151             final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener) {
152         super(readings, initialPosition, listener);
153         preliminarySubsetSize = getMinReadings();
154     }
155 
156     /**
157      * Creates a robust 2D position radio source estimator.
158      *
159      * @param method robust estimator method.
160      * @param <S>    a {@link RadioSource} type.
161      * @return a new robust 2D position radio source estimator.
162      */
163     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
164             final RobustEstimatorMethod method) {
165         return switch (method) {
166             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>();
167             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>();
168             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>();
169             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>();
170             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>();
171         };
172     }
173 
174     /**
175      * Creates a robust 2D position radio source estimator.
176      *
177      * @param readings radio signal ranging readings belonging to the same radio source.
178      * @param method   robust estimator method.
179      * @param <S>      a {@link RadioSource} type.
180      * @return a new robust 2D position radio source estimator.
181      */
182     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
183             final List<? extends RangingReadingLocated<S, Point2D>> readings, final RobustEstimatorMethod method) {
184         return switch (method) {
185             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings);
186             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings);
187             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings);
188             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(readings);
189             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(readings);
190         };
191     }
192 
193     /**
194      * Creates a robust 2D position radio source estimator.
195      *
196      * @param listener listener in charge of attending events raised by this instance.
197      * @param method   robust estimator method.
198      * @param <S>      a {@link RadioSource} type.
199      * @return a new robust 2D position radio source estimator.
200      */
201     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
202             final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener, final RobustEstimatorMethod method) {
203         return switch (method) {
204             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(listener);
205             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(listener);
206             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(listener);
207             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(listener);
208             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(listener);
209         };
210     }
211 
212     /**
213      * Creates a robust 2D position radio source estimator.
214      *
215      * @param readings radio signal ranging readings belonging to the same radio source.
216      * @param listener listener in charge of attending events raised by this instance.
217      * @param method   robust estimator method.
218      * @param <S>      a {@link RadioSource} type.
219      * @return a new robust 2D position radio source estimator.
220      */
221     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
222             final List<? extends RangingReadingLocated<S, Point2D>> readings,
223             final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener, final RobustEstimatorMethod method) {
224         return switch (method) {
225             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings, listener);
226             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings, listener);
227             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings, listener);
228             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(readings, listener);
229             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(readings, listener);
230         };
231     }
232 
233     /**
234      * Creates a robust 2D position radio source estimator.
235      *
236      * @param initialPosition initial position to start the estimation or radio
237      *                        source position.
238      * @param method          robust estimator method.
239      * @param <S>             a {@link RadioSource} type.
240      * @return a new robust 2D position radio source estimator.
241      */
242     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
243             final Point2D initialPosition, final RobustEstimatorMethod method) {
244         return switch (method) {
245             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(initialPosition);
246             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(initialPosition);
247             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(initialPosition);
248             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(initialPosition);
249             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(initialPosition);
250         };
251     }
252 
253     /**
254      * Creates a robust 2D position radio source estimator.
255      *
256      * @param readings        radio signal ranging readings belonging to the same radio source.
257      * @param initialPosition initial position to start the estimation or radio
258      *                        source position.
259      * @param method          robust estimator method.
260      * @param <S>             a {@link RadioSource} type.
261      * @return a new robust 2D position radio source estimator.
262      */
263     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
264             final List<? extends RangingReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
265             final RobustEstimatorMethod method) {
266         return switch (method) {
267             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
268             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
269             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
270             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
271             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
272         };
273     }
274 
275     /**
276      * Creates a robust 2D position radio source estimator.
277      *
278      * @param initialPosition initial position to start the estimation or radio
279      *                        source position.
280      * @param listener        listener in charge of attending events raised by this instance.
281      * @param method          robust estimator method.
282      * @param <S>             a {@link RadioSource} type.
283      * @return a new robust 2D position radio source estimator.
284      */
285     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
286             final Point2D initialPosition, final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener,
287             final RobustEstimatorMethod method) {
288         return switch (method) {
289             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
290             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
291             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
292             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
293             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
294         };
295     }
296 
297     /**
298      * Creates a robust 2D position radio source estimator.
299      *
300      * @param readings        radio signal ranging readings belonging to the same radio source.
301      * @param initialPosition initial position to start the estimation or radio
302      *                        source position.
303      * @param listener        listener in charge of attending events raised by this instance.
304      * @param method          robust estimator method.
305      * @param <S>             a {@link RadioSource} type.
306      * @return a new robust 2D position radio source estimator.
307      */
308     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
309             final List<? extends RangingReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
310             final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener, final RobustEstimatorMethod method) {
311         return switch (method) {
312             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
313             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
314             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
315             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
316             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
317         };
318     }
319 
320     /**
321      * Creates a robust 2D position radio source estimator.
322      *
323      * @param qualityScores quality scores corresponding to each provided
324      *                      sample. The larger the score value the better
325      *                      the quality of the sample.
326      * @param method        robust estimator method.
327      * @param <S>           a {@link RadioSource} type.
328      * @return a new robust 2D position radio source estimator.
329      */
330     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
331             final double[] qualityScores, final RobustEstimatorMethod method) {
332         return switch (method) {
333             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>();
334             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>();
335             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>();
336             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores);
337             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores);
338         };
339     }
340 
341     /**
342      * Creates a robust 2D position radio source estimator.
343      *
344      * @param qualityScores quality scores corresponding to each provided
345      *                      sample. The larger the score value the better
346      *                      the quality of the sample.*
347      * @param readings      radio signal ranging readings belonging to the same radio source.
348      * @param method        robust estimator method.
349      * @param <S>           a {@link RadioSource} type.
350      * @return a new robust 2D position radio source estimator.
351      */
352     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
353             final double[] qualityScores, final List<? extends RangingReadingLocated<S, Point2D>> readings,
354             final RobustEstimatorMethod method) {
355         return switch (method) {
356             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings);
357             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings);
358             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings);
359             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores, readings);
360             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores, readings);
361         };
362     }
363 
364     /**
365      * Creates a robust 2D position radio source estimator.
366      *
367      * @param qualityScores quality scores corresponding to each provided
368      *                      sample. The larger the score value the better
369      *                      the quality of the sample.*
370      * @param listener      listener in charge of attending events raised by this instance.
371      * @param method        robust estimator method.
372      * @param <S>           a {@link RadioSource} type.
373      * @return a new robust 2D position radio source estimator.
374      */
375     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
376             final double[] qualityScores, final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener,
377             final RobustEstimatorMethod method) {
378         return switch (method) {
379             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(listener);
380             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(listener);
381             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(listener);
382             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores, listener);
383             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores, listener);
384         };
385     }
386 
387     /**
388      * Creates a robust 2D position radio source estimator.
389      *
390      * @param qualityScores quality scores corresponding to each provided
391      *                      sample. The larger the score value the better
392      *                      the quality of the sample.**
393      * @param readings      radio signal ranging readings belonging to the same radio source.
394      * @param listener      listener in charge of attending events raised by this instance.
395      * @param method        robust estimator method.
396      * @param <S>           a {@link RadioSource} type.
397      * @return a new robust 2D position radio source estimator.
398      */
399     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
400             final double[] qualityScores, final List<? extends RangingReadingLocated<S, Point2D>> readings,
401             final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener, final RobustEstimatorMethod method) {
402         return switch (method) {
403             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings, listener);
404             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings, listener);
405             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings, listener);
406             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores, readings, listener);
407             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores, readings, listener);
408         };
409     }
410 
411     /**
412      * Creates a robust 2D position radio source estimator.
413      *
414      * @param qualityScores   quality scores corresponding to each provided
415      *                        sample. The larger the score value the better
416      *                        the quality of the sample.*
417      * @param initialPosition initial position to start the estimation or radio
418      *                        source position.
419      * @param method          robust estimator method.
420      * @param <S>             a {@link RadioSource} type.
421      * @return a new robust 2D position radio source estimator.
422      */
423     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
424             final double[] qualityScores, final Point2D initialPosition, final RobustEstimatorMethod method) {
425         return switch (method) {
426             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(initialPosition);
427             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(initialPosition);
428             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(initialPosition);
429             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores, initialPosition);
430             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores, initialPosition);
431         };
432     }
433 
434     /**
435      * Creates a robust 2D position radio source estimator.
436      *
437      * @param qualityScores   quality scores corresponding to each provided
438      *                        sample. The larger the score value the better
439      *                        the quality of the sample.*
440      * @param readings        radio signal ranging readings belonging to the same radio source.
441      * @param initialPosition initial position to start the estimation or radio
442      *                        source position.
443      * @param method          robust estimator method.
444      * @param <S>             a {@link RadioSource} type.
445      * @return a new robust 2D position radio source estimator.
446      */
447     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
448             final double[] qualityScores, final List<? extends RangingReadingLocated<S, Point2D>> readings,
449             final Point2D initialPosition, final RobustEstimatorMethod method) {
450         return switch (method) {
451             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
452             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
453             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition);
454             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores, readings, initialPosition);
455             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores, readings, initialPosition);
456         };
457     }
458 
459     /**
460      * Creates a robust 2D position radio source estimator.
461      *
462      * @param qualityScores   quality scores corresponding to each provided
463      *                        sample. The larger the score value the better
464      *                        the quality of the sample.*
465      * @param initialPosition initial position to start the estimation or radio
466      *                        source position.
467      * @param listener        listener in charge of attending events raised by this instance.
468      * @param method          robust estimator method.
469      * @param <S>             a {@link RadioSource} type.
470      * @return a new robust 2D position radio source estimator.
471      */
472     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
473             final double[] qualityScores, final Point2D initialPosition,
474             final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener, final RobustEstimatorMethod method) {
475         return switch (method) {
476             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
477             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
478             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(initialPosition, listener);
479             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores, initialPosition, listener);
480             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores, initialPosition, listener);
481         };
482     }
483 
484     /**
485      * Creates a robust 2D position radio source estimator.
486      *
487      * @param qualityScores   quality scores corresponding to each provided
488      *                        sample. The larger the score value the better
489      *                        the quality of the sample.*
490      * @param readings        radio signal ranging readings belonging to the same radio source.
491      * @param initialPosition initial position to start the estimation or radio
492      *                        source position.
493      * @param listener        listener in charge of attending events raised by this instance.
494      * @param method          robust estimator method.
495      * @param <S>             a {@link RadioSource} type.
496      * @return a new robust 2D position radio source estimator.
497      */
498     public static <S extends RadioSource> RobustRangingRadioSourceEstimator2D<S> create(
499             final double[] qualityScores, final List<? extends RangingReadingLocated<S, Point2D>> readings,
500             final Point2D initialPosition, final RobustRangingRadioSourceEstimatorListener<S, Point2D> listener,
501             final RobustEstimatorMethod method) {
502         return switch (method) {
503             case RANSAC -> new RANSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
504             case LMEDS -> new LMedSRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
505             case MSAC -> new MSACRobustRangingRadioSourceEstimator2D<>(readings, initialPosition, listener);
506             case PROSAC -> new PROSACRobustRangingRadioSourceEstimator2D<>(qualityScores, readings, initialPosition,
507                     listener);
508             default -> new PROMedSRobustRangingRadioSourceEstimator2D<>(qualityScores, readings, initialPosition,
509                     listener);
510         };
511     }
512 
513     /**
514      * Gets minimum required number of readings to estimate position of radio source,
515      * which is 3 readings.
516      *
517      * @return minimum required number of readings.
518      */
519     @Override
520     public int getMinReadings() {
521         return Point2D.POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH + 1;
522     }
523 
524     /**
525      * Gets number of dimensions of position points.
526      * This is always 2.
527      *
528      * @return number of dimensions of position points.
529      */
530     @Override
531     public int getNumberOfDimensions() {
532         return Point2D.POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH;
533     }
534 
535     /**
536      * Gets estimated located radio source.
537      *
538      * @return estimated located radio source or null.
539      */
540     @SuppressWarnings("unchecked")
541     @Override
542     public RadioSourceLocated<Point2D> getEstimatedRadioSource() {
543         final var readings = getReadings();
544         if (readings == null || readings.isEmpty()) {
545             return null;
546         }
547         final var source = readings.get(0).getSource();
548 
549         final var estimatedPosition = getEstimatedPosition();
550         if (estimatedPosition == null) {
551             return null;
552         }
553 
554         final var estimatedPositionCovariance = getEstimatedPositionCovariance();
555 
556         if (source instanceof WifiAccessPoint accessPoint) {
557             return new WifiAccessPointLocated2D(accessPoint.getBssid(), accessPoint.getFrequency(),
558                     accessPoint.getSsid(), estimatedPosition, estimatedPositionCovariance);
559         } else if (source instanceof Beacon beacon) {
560             return new BeaconLocated2D(beacon.getIdentifiers(), beacon.getTransmittedPower(), beacon.getFrequency(),
561                     beacon.getBluetoothAddress(), beacon.getBeaconTypeCode(), beacon.getManufacturer(),
562                     beacon.getServiceUuid(), beacon.getBluetoothName(), estimatedPosition, estimatedPositionCovariance);
563         } else {
564             return null;
565         }
566     }
567 
568     /**
569      * Indicates whether an homogeneous linear solver is used to estimate an initial
570      * position.
571      *
572      * @return true if homogeneous linear solver is used, false if an inhomogeneous linear
573      * one is used instead.
574      */
575     @Override
576     public boolean isHomogeneousLinearSolverUsed() {
577         return innerEstimator.isHomogeneousLinearSolverUsed();
578     }
579 
580     /**
581      * Specifies whether an homogeneous linear solver is used to estimate an initial
582      * position.
583      *
584      * @param useHomogeneousLinearSolver true if homogeneous linear solver is used, false
585      *                                   if an inhomogeneous linear one is used instead.
586      * @throws LockedException if estimator is locked.
587      */
588     @Override
589     public void setHomogeneousLinearSolverUsed(final boolean useHomogeneousLinearSolver) throws LockedException {
590         if (isLocked()) {
591             throw new LockedException();
592         }
593         innerEstimator.setHomogeneousLinearSolverUsed(useHomogeneousLinearSolver);
594     }
595 
596     /**
597      * Solves preliminary solution for a subset of samples.
598      *
599      * @param samplesIndices indices of subset samples.
600      * @param solutions      instance where solution will be stored.
601      */
602     @Override
603     protected void solvePreliminarySolutions(final int[] samplesIndices, final List<Solution<Point2D>> solutions) {
604         try {
605             innerReadings.clear();
606             for (final var samplesIndex : samplesIndices) {
607                 innerReadings.add(readings.get(samplesIndex));
608             }
609 
610             // initial position might or might not be available
611             innerEstimator.setInitialPosition(initialPosition);
612 
613             innerEstimator.setReadings(innerReadings);
614 
615             // for preliminary solutions, non-linear solver is not needed, and if no
616             // initial position is used, we can obtain faster solutions disabling
617             // non-linear solver and using a linear one only (because covariance is not
618             // required)
619             innerEstimator.setNonLinearSolverEnabled(initialPosition != null);
620 
621             // indicates whether readings position covariances must be taken into account
622             innerEstimator.setUseReadingPositionCovariances(useReadingPositionCovariances);
623 
624             innerEstimator.estimate();
625 
626             final var estimatedPosition = innerEstimator.getEstimatedPosition();
627             solutions.add(new Solution<>(estimatedPosition));
628         } catch (final NavigationException ignore) {
629             // if anything fails, no solution is added
630         }
631     }
632 
633     /**
634      * Attempts to refine estimated position and transmitted power contained in
635      * provided solution if refinement is requested.
636      * This method sets a refined result and transmitted power or provided input
637      * result if refinement is not requested or has failed.
638      * If refinement is enabled, and it is requested to keep covariance, this method
639      * will also keep covariance of refined result.
640      * solution if not requested or refinement failed.
641      *
642      * @param result result to be refined.
643      */
644     protected void attemptRefine(final Solution<Point2D> result) {
645         final var initialPosition = result.getEstimatedPosition();
646 
647         if (refineResult && inliersData != null) {
648             final var inliers = inliersData.getInliers();
649             final var nSamples = readings.size();
650 
651             innerReadings.clear();
652 
653             for (var i = 0; i < nSamples; i++) {
654                 if (inliers.get(i)) {
655                     // sample is inlier
656                     innerReadings.add(readings.get(i));
657                 }
658             }
659 
660             try {
661                 innerEstimator.setInitialPosition(initialPosition);
662                 innerEstimator.setReadings(innerReadings);
663 
664                 innerEstimator.setNonLinearSolverEnabled(true);
665                 innerEstimator.setUseReadingPositionCovariances(useReadingPositionCovariances);
666                 innerEstimator.estimate();
667 
668                 final var cov = innerEstimator.getEstimatedCovariance();
669                 if (keepCovariance && cov != null) {
670                     // keep covariance
671                     estimatedPositionCovariance = covariance = cov;
672 
673                 } else {
674                     covariance = null;
675                     estimatedPositionCovariance = null;
676                 }
677 
678                 estimatedPosition = innerEstimator.getEstimatedPosition();
679             } catch (final Exception e) {
680                 // refinement failed, so we return input value, and covariance
681                 // becomes unavailable
682                 covariance = null;
683                 estimatedPositionCovariance = null;
684 
685                 estimatedPosition = initialPosition;
686             }
687         } else {
688             covariance = null;
689             estimatedPositionCovariance = null;
690 
691             estimatedPosition = initialPosition;
692         }
693     }
694 }