1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.navigation.utils;
17
18 import com.irurueta.navigation.geodesic.Geodesic;
19 import com.irurueta.units.Distance;
20 import com.irurueta.units.DistanceUnit;
21
22 import java.text.DecimalFormat;
23 import java.util.StringTokenizer;
24
25
26
27
28 public class LocationUtils {
29
30
31
32
33 public static final int FORMAT_DEGREES = 0;
34
35
36
37
38
39
40 public static final int FORMAT_MINUTES = 1;
41
42
43
44
45
46
47
48 public static final int FORMAT_SECONDS = 2;
49
50
51
52
53
54 private LocationUtils() {
55 }
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public static String convert(double coordinate, final int outputType) {
74 if (coordinate < -180.0 || coordinate > 180.0 || Double.isNaN(coordinate)) {
75 throw new IllegalArgumentException();
76 }
77 if ((outputType != FORMAT_DEGREES) && (outputType != FORMAT_MINUTES) && (outputType != FORMAT_SECONDS)) {
78 throw new IllegalArgumentException();
79 }
80
81 final var sb = new StringBuilder();
82
83
84 if (coordinate < 0) {
85 sb.append('-');
86 coordinate = -coordinate;
87 }
88
89 final var df = new DecimalFormat("###.#####");
90 if (outputType == FORMAT_MINUTES || outputType == FORMAT_SECONDS) {
91 final var degrees = (int) Math.floor(coordinate);
92 sb.append(degrees);
93 sb.append(':');
94 coordinate -= degrees;
95 coordinate *= 60.0;
96 if (outputType == FORMAT_SECONDS) {
97 final var minutes = (int) Math.floor(coordinate);
98 sb.append(minutes);
99 sb.append(':');
100 coordinate -= minutes;
101 coordinate *= 60.0;
102 }
103 }
104 sb.append(df.format(coordinate));
105 return sb.toString();
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 public static double convert(String coordinate) {
122
123 if (coordinate == null) {
124 throw new NullPointerException();
125 }
126
127 var negative = false;
128 if (coordinate.charAt(0) == '-') {
129 coordinate = coordinate.substring(1);
130 negative = true;
131 }
132
133 final var st = new StringTokenizer(coordinate, ":");
134 final var tokens = st.countTokens();
135 if (tokens < 1) {
136 throw new IllegalArgumentException();
137 }
138 try {
139 final var degrees = st.nextToken();
140 double val;
141 if (tokens == 1) {
142 val = Double.parseDouble(degrees);
143 return negative ? -val : val;
144 }
145
146 final var minutes = st.nextToken();
147 final var deg = Integer.parseInt(degrees);
148 double min;
149 var sec = 0.0;
150 var secPresent = false;
151
152 if (st.hasMoreTokens()) {
153 min = Integer.parseInt(minutes);
154 final var seconds = st.nextToken();
155 sec = Double.parseDouble(seconds);
156 secPresent = true;
157 } else {
158 min = Double.parseDouble(minutes);
159 }
160
161 final var isNegative180 = negative && (deg == 180) && (min == 0) && (sec == 0);
162
163
164 if ((deg < 0.0) || (deg > 179 && !isNegative180)) {
165 throw new IllegalArgumentException();
166 }
167
168
169 if (min < 0 || min >= 60 || (secPresent && (min > 59))) {
170 throw new IllegalArgumentException();
171 }
172
173
174 if (sec < 0 || sec >= 60) {
175 throw new IllegalArgumentException();
176 }
177
178 val = deg * 3600.0 + min * 60.0 + sec;
179 val /= 3600.0;
180 return negative ? -val : val;
181 } catch (final NumberFormatException nfe) {
182 throw new IllegalArgumentException();
183 }
184 }
185
186
187
188
189
190
191
192
193
194
195
196 public static void distanceAndBearing(
197 final double startLatitude, final double startLongitude, final double endLatitude,
198 final double endLongitude, final BearingDistance results) {
199
200 final var data = Geodesic.WGS84.inverse(startLatitude, startLongitude, endLatitude, endLongitude);
201 results.startLatitude = data.getLat1();
202 results.startLongitude = data.getLon1();
203 results.endLatitude = data.getLat2();
204 results.endLongitude = data.getLon2();
205 results.distance = data.getS12();
206 results.initialBearing = data.getAzi1();
207 results.finalBearing = data.getAzi2();
208 }
209
210
211
212
213
214
215
216
217
218
219
220 public static BearingDistance distanceAndBearing(
221 final double startLatitude, final double startLongitude, final double endLatitude,
222 final double endLongitude) {
223 final var results = new BearingDistance();
224 distanceAndBearing(startLatitude, startLongitude, endLatitude, endLongitude, results);
225 return results;
226 }
227
228
229
230
231
232
233
234
235
236
237
238
239
240 public static void distanceAndBearing(
241 final double startLatitude, final double startLongitude, final double endLatitude,
242 final double endLongitude, final double[] results) {
243 if (results.length == 0) {
244 throw new IllegalArgumentException();
245 }
246
247 final var data = Geodesic.WGS84.inverse(startLatitude, startLongitude, endLatitude, endLongitude);
248 results[0] = data.getS12();
249 if (results.length > 1) {
250 results[1] = data.getAzi1();
251 if (results.length > 2) {
252 results[2] = data.getAzi2();
253 }
254 }
255 }
256
257
258
259
260
261
262
263
264
265
266 public static double distanceBetweenMeters(
267 final double startLatitude, final double startLongitude, final double endLatitude,
268 final double endLongitude) {
269
270 return Geodesic.WGS84.inverse(startLatitude, startLongitude, endLatitude, endLongitude).getS12();
271 }
272
273
274
275
276
277
278
279
280
281
282 public static Distance distanceBetween(
283 final double startLatitude, final double startLongitude, final double endLatitude,
284 final double endLongitude) {
285 return new Distance(distanceBetweenMeters(startLatitude, startLongitude, endLatitude, endLongitude),
286 DistanceUnit.METER);
287 }
288
289
290
291
292
293
294
295
296
297
298
299 public static Distance distanceBetween(
300 final double startLatitude, final double startLongitude, final double endLatitude,
301 final double endLongitude, final Distance result) {
302 result.setValue(distanceBetweenMeters(startLatitude, startLongitude, endLatitude, endLongitude));
303 result.setUnit(DistanceUnit.METER);
304 return result;
305 }
306
307
308
309
310
311 public static class BearingDistance {
312
313
314
315 private double startLatitude;
316
317
318
319
320 private double startLongitude;
321
322
323
324
325 private double endLatitude;
326
327
328
329
330 private double endLongitude;
331
332
333
334
335 private double distance = 0.0f;
336
337
338
339
340 private double initialBearing = 0.0f;
341
342
343
344
345 private double finalBearing = 0.0f;
346
347
348
349
350
351
352 public double getStartLatitude() {
353 return startLatitude;
354 }
355
356
357
358
359
360
361 public double getStartLongitude() {
362 return startLongitude;
363 }
364
365
366
367
368
369
370 public double getEndLatitude() {
371 return endLatitude;
372 }
373
374
375
376
377
378
379 public double getEndLongitude() {
380 return endLongitude;
381 }
382
383
384
385
386
387
388 public double getDistanceMeters() {
389 return distance;
390 }
391
392
393
394
395
396
397 public Distance getDistance() {
398 return new Distance(distance, DistanceUnit.METER);
399 }
400
401
402
403
404
405
406
407 public Distance getDistance(final Distance result) {
408 result.setValue(distance);
409 result.setUnit(DistanceUnit.METER);
410 return result;
411 }
412
413
414
415
416
417
418 public double getInitialBearing() {
419 return initialBearing;
420 }
421
422
423
424
425
426
427 public double getFinalBearing() {
428 return finalBearing;
429 }
430 }
431 }