1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.navigation.indoor.position;
17
18 import com.irurueta.geometry.Point;
19 import com.irurueta.navigation.indoor.Fingerprint;
20 import com.irurueta.navigation.indoor.RadioSource;
21 import com.irurueta.navigation.indoor.RadioSourceLocated;
22 import com.irurueta.navigation.indoor.Reading;
23 import com.irurueta.navigation.indoor.ReadingType;
24
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Comparator;
28 import java.util.HashMap;
29 import java.util.List;
30
31
32
33
34
35
36
37
38 public class ReadingSorter<P extends Point<?>, R extends Reading<? extends RadioSource>> {
39
40
41
42
43 private final List<? extends RadioSourceLocated<P>> sources;
44
45
46
47
48 private final Fingerprint<? extends RadioSource, ? extends R> fingerprint;
49
50
51
52
53 private final double[] sourceQualityScores;
54
55
56
57
58 private final double[] fingerprintReadingsQualityScores;
59
60
61
62
63 private List<RadioSourceSourceWithQualityScore<P, R>> sortedSourcesAndReadings;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 ReadingSorter(final List<? extends RadioSourceLocated<P>> sources,
82 final Fingerprint<? extends RadioSource, ? extends R> fingerprint,
83 final double[] sourceQualityScores, final double[] fingerprintReadingsQualityScores) {
84 if (sources.size() != sourceQualityScores.length) {
85 throw new IllegalArgumentException();
86 }
87
88 if (fingerprint.getReadings().size() != fingerprintReadingsQualityScores.length) {
89 throw new IllegalArgumentException();
90 }
91
92 this.sources = sources;
93 this.fingerprint = fingerprint;
94 this.sourceQualityScores = sourceQualityScores;
95 this.fingerprintReadingsQualityScores = fingerprintReadingsQualityScores;
96 }
97
98
99
100
101
102
103 public List<RadioSourceLocated<P>> getSources() {
104
105 return (List<RadioSourceLocated<P>>) sources;
106 }
107
108
109
110
111
112
113 public Fingerprint<RadioSource, Reading<RadioSource>> getFingerprint() {
114
115 return (Fingerprint<RadioSource, Reading<RadioSource>>) fingerprint;
116 }
117
118
119
120
121
122
123 double[] getSourceQualityScores() {
124 return sourceQualityScores;
125 }
126
127
128
129
130
131
132 double[] getFingerprintReadingsQualityScores() {
133 return fingerprintReadingsQualityScores;
134 }
135
136
137
138
139 void sort() {
140
141 final var sourcesMap = new HashMap<RadioSourceLocated<P>, RadioSourceSourceWithQualityScore<P, R>>();
142
143
144 final var sourcesWithQualityScores = new ArrayList<RadioSourceSourceWithQualityScore<P, R>>();
145 var sourcePosition = 0;
146 for (final var source : sources) {
147 final var sourceWithQualityScore = new RadioSourceSourceWithQualityScore<P, R>();
148 sourceWithQualityScore.source = source;
149 sourceWithQualityScore.qualityScore = sourceQualityScores[sourcePosition];
150 sourceWithQualityScore.position = sourcePosition;
151 sourceWithQualityScore.readingsWithQualityScores = new ArrayList<>();
152
153 sourcesWithQualityScores.add(sourceWithQualityScore);
154
155 sourcesMap.put(source, sourceWithQualityScore);
156
157 sourcePosition++;
158 }
159
160
161 var readingPosition = 0;
162 for (@SuppressWarnings("unchecked") final var reading : fingerprint.getReadings()) {
163 if (!(reading.getSource() instanceof RadioSourceLocated)) {
164 continue;
165 }
166
167
168 final var radioSourceLocated = (RadioSourceLocated<P>) reading.getSource();
169 final var sourceWithQualityScore = sourcesMap.get(radioSourceLocated);
170
171 if (sourceWithQualityScore == null) {
172 continue;
173 }
174
175 final var readingsWithQualityScores = sourceWithQualityScore.readingsWithQualityScores;
176
177 final var readingWithQualityScore = new ReadingWithQualityScore<R>();
178 readingWithQualityScore.reading = reading;
179 readingWithQualityScore.qualityScore = fingerprintReadingsQualityScores[readingPosition];
180 readingWithQualityScore.position = readingPosition;
181
182 readingsWithQualityScores.add(readingWithQualityScore);
183
184 readingPosition++;
185 }
186
187
188 for (final var sourceWithQualityScore : sourcesWithQualityScores) {
189
190
191
192 final ReadingWithQualityScore<R>[] readingsWithQualityScoresArray =
193 new ReadingWithQualityScore[sourceWithQualityScore.readingsWithQualityScores.size()];
194 sourceWithQualityScore.readingsWithQualityScores.toArray(readingsWithQualityScoresArray);
195 Arrays.sort(readingsWithQualityScoresArray, new ReadingComparator<>());
196
197 sourceWithQualityScore.readingsWithQualityScores = Arrays.asList(readingsWithQualityScoresArray);
198 }
199
200
201
202
203 final RadioSourceSourceWithQualityScore<P, R>[] sourcesWithQualityScoresArray =
204 new RadioSourceSourceWithQualityScore[sourcesWithQualityScores.size()];
205 sourcesWithQualityScores.toArray(sourcesWithQualityScoresArray);
206 Arrays.sort(sourcesWithQualityScoresArray, new RadioSourceComparator<>());
207
208 sortedSourcesAndReadings = Arrays.asList(sourcesWithQualityScoresArray);
209 }
210
211
212
213
214
215
216 List<RadioSourceSourceWithQualityScore<P, R>> getSortedSourcesAndReadings() {
217 return sortedSourcesAndReadings;
218 }
219
220
221
222
223
224
225 static class ReadingWithQualityScore<R extends Reading<? extends RadioSource>> {
226
227
228
229 R reading;
230
231
232
233
234 double qualityScore;
235
236
237
238
239 int position;
240 }
241
242
243
244
245
246
247
248 static class RadioSourceSourceWithQualityScore<P extends Point<?>, R extends Reading<? extends RadioSource>> {
249
250
251
252 RadioSourceLocated<P> source;
253
254
255
256
257 double qualityScore;
258
259
260
261
262 int position;
263
264 List<ReadingWithQualityScore<R>> readingsWithQualityScores;
265 }
266
267
268
269
270
271
272 private static class ReadingComparator<R extends Reading<? extends RadioSource>> implements
273 Comparator<ReadingWithQualityScore<R>> {
274
275
276
277
278
279
280
281
282
283 @Override
284 public int compare(final ReadingWithQualityScore<R> o1, final ReadingWithQualityScore<R> o2) {
285
286
287
288 if (o1.reading.getType() != o2.reading.getType()) {
289 switch (o1.reading.getType()) {
290 case RANGING_READING:
291
292 return -1;
293
294 case RANGING_AND_RSSI_READING:
295 if (o2.reading.getType() == ReadingType.RANGING_READING) {
296
297
298 return 1;
299 } else {
300
301
302 return -1;
303 }
304 case RSSI_READING:
305 default:
306
307 return 1;
308 }
309 }
310
311
312
313
314 return Double.compare(o2.qualityScore, o1.qualityScore);
315 }
316 }
317
318
319
320
321
322
323
324 private static class RadioSourceComparator<P extends Point<?>, R extends Reading<? extends RadioSource>> implements
325 Comparator<RadioSourceSourceWithQualityScore<P, R>> {
326
327
328
329
330
331
332
333
334
335 @Override
336 public int compare(final RadioSourceSourceWithQualityScore<P, R> o1,
337 final RadioSourceSourceWithQualityScore<P, R> o2) {
338 return Double.compare(o2.qualityScore, o1.qualityScore);
339 }
340 }
341 }