1 /*
2 * Copyright (C) 2019 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.frames;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.algebra.WrongSizeException;
20 import com.irurueta.geometry.InhomogeneousPoint3D;
21 import com.irurueta.geometry.Point3D;
22 import com.irurueta.units.Distance;
23 import com.irurueta.units.DistanceConverter;
24 import com.irurueta.units.DistanceUnit;
25
26 import java.io.Serializable;
27 import java.util.Objects;
28
29 /**
30 * Contains body cartesian position with respect Earth, resolved about ECEF frame
31 * and expressed in meters (m).
32 */
33 public class ECEFPosition implements Serializable, Cloneable {
34
35 /**
36 * Number of components.
37 */
38 public static final int COMPONENTS = 3;
39
40 /**
41 * Cartesian x coordinate of body position expressed in meters (m) with respect ECEF frame, resolved
42 * along ECEF axes.
43 */
44 private double x;
45
46 /**
47 * Cartesian y coordinate of body position expressed in meters (m) with respect ECEF frame, resolved
48 * along ECEF axes.
49 */
50 private double y;
51
52 /**
53 * Cartesian z coordinate of body position expressed in meters (m) with respect ECEF frame, resolved
54 * along ECEF axes.
55 */
56 private double z;
57
58 /**
59 * Constructor.
60 */
61 public ECEFPosition() {
62 }
63
64 /**
65 * Constructor.
66 *
67 * @param x cartesian x coordinate of body position expressed in meters (m) and
68 * resolved along ECEF-frame axes.
69 * @param y cartesian y coordinate of body position expressed in meters (m) and
70 * resolved along ECEF-frame axes.
71 * @param z cartesian z coordinate of body position expressed in meters (m) and
72 * resolved along ECEF-frame axes.
73 */
74 public ECEFPosition(final double x, final double y, final double z) {
75 setCoordinates(x, y, z);
76 }
77
78 /**
79 * Constructor.
80 *
81 * @param x cartesian x coordinate of body position resolved along ECEF-frame axes.
82 * @param y cartesian y coordinate of body position resolved along ECEF-frame axes.
83 * @param z cartesian z coordinate of body position resolved along ECEF-frame axes.
84 */
85 public ECEFPosition(final Distance x, final Distance y, final Distance z) {
86 setCoordinates(x, y, z);
87 }
88
89 /**
90 * Constructor.
91 *
92 * @param input ECEF body position to copy data from.
93 */
94 public ECEFPosition(final ECEFPosition input) {
95 copyFrom(input);
96 }
97
98 /**
99 * Gets cartesian x coordinate of body position expressed in meters (m) with respect
100 * ECEF frame, resolved along ECEF axes.
101 *
102 * @return cartesian x coordinate of body position.
103 */
104 public double getX() {
105 return x;
106 }
107
108 /**
109 * Sets cartesian x coordinate of body position expressed in meters (m) with respect
110 * ECEF frame, resolved along ECEF axes.
111 *
112 * @param x cartesian x coordinate of body position.
113 */
114 public void setX(final double x) {
115 this.x = x;
116 }
117
118 /**
119 * Gets cartesian y coordinate of body position expressed in meters (m) with respect
120 * ECEF frame, resolved along ECEF axes.
121 *
122 * @return cartesian y coordinate of body position.
123 */
124 public double getY() {
125 return y;
126 }
127
128 /**
129 * Sets cartesian y coordinate of body position expressed in meters (m) with respect
130 * ECEF frame, resolved along ECEF axes.
131 *
132 * @param y cartesian y coordinate of body position.
133 */
134 public void setY(final double y) {
135 this.y = y;
136 }
137
138 /**
139 * Gets cartesian z coordinate of body position expressed in meters (m) with respect
140 * ECEF frame, resolved along ECEF axes.
141 *
142 * @return z coordinate of body position.
143 */
144 public double getZ() {
145 return z;
146 }
147
148 /**
149 * Sets cartesian z coordinate of body position expressed in meters (m) with respect
150 * ECEF frame, resolved along ECEF axes.
151 *
152 * @param z cartesian z coordinate of body position.
153 */
154 public void setZ(final double z) {
155 this.z = z;
156 }
157
158 /**
159 * Sets cartesian coordinates of body position expressed in meters (m) and resolved
160 * along ECEF-frame axes.
161 *
162 * @param x cartesian x coordinate of body position.
163 * @param y cartesian y coordinate of body position.
164 * @param z cartesian z coordinate of body position.
165 */
166 public void setCoordinates(final double x, final double y, final double z) {
167 this.x = x;
168 this.y = y;
169 this.z = z;
170 }
171
172 /**
173 * Gets body position expressed in meters (m) and resolved along ECEF-frame axes.
174 *
175 * @return body position.
176 */
177 public Point3D getPosition() {
178 return new InhomogeneousPoint3D(x, y, z);
179 }
180
181 /**
182 * Gets body position expressed in meters (m) and resolved along ECEF-frame axes.
183 *
184 * @param result instance where position data is copied to.
185 */
186 public void getPosition(final Point3D result) {
187 result.setInhomogeneousCoordinates(x, y, z);
188 }
189
190 /**
191 * Sets body position expressed in meters (m) and resolved along ECEF-frame axes.
192 *
193 * @param point body position to be set.
194 */
195 public void setPosition(final Point3D point) {
196 x = point.getInhomX();
197 y = point.getInhomY();
198 z = point.getInhomZ();
199 }
200
201 /**
202 * Gets cartesian x coordinate of body position resolved along ECEF-frame axes.
203 *
204 * @param result instance where cartesian x coordinate of body position will be
205 * stored.
206 */
207 public void getDistanceX(final Distance result) {
208 result.setValue(x);
209 result.setUnit(DistanceUnit.METER);
210 }
211
212 /**
213 * Gets cartesian x coordinate of body position resolved along ECEF-frame axes.
214 *
215 * @return x coordinate of body position resolved along ECEF-frame axes.
216 */
217 public Distance getDistanceX() {
218 return new Distance(x, DistanceUnit.METER);
219 }
220
221 /**
222 * Sets cartesian x coordinate of body position resolved along ECEF-frame axes.
223 *
224 * @param x cartesian x coordinate of body position to be set.
225 */
226 public void setX(final Distance x) {
227 this.x = convertDistance(x);
228 }
229
230 /**
231 * Gets cartesian y coordinate of body position resolved along ECEF-frame axes.
232 *
233 * @param result instance where cartesian y coordinate of body position will be
234 * stored.
235 */
236 public void getDistanceY(final Distance result) {
237 result.setValue(y);
238 result.setUnit(DistanceUnit.METER);
239 }
240
241 /**
242 * Gets cartesian y coordinate of body position resolved along ECEF-frame axes.
243 *
244 * @return y coordinate of body position resolved along ECEF-frame axes.
245 */
246 public Distance getDistanceY() {
247 return new Distance(y, DistanceUnit.METER);
248 }
249
250 /**
251 * Sets cartesian y coordinate of body position resolved along ECEF-frame axes.
252 *
253 * @param y cartesian y coordinate of body position to be set.
254 */
255 public void setY(final Distance y) {
256 this.y = convertDistance(y);
257 }
258
259 /**
260 * Gets cartesian z coordinate of body position resolved along ECEF-frame axes.
261 *
262 * @param result instance where cartesian z coordinate of body position will be
263 * stored.
264 */
265 public void getDistanceZ(final Distance result) {
266 result.setValue(z);
267 result.setUnit(DistanceUnit.METER);
268 }
269
270 /**
271 * Gets cartesian z coordinate of body position resolved along ECEF-frame axes.
272 *
273 * @return z coordinate of body position resolved along ECEF-frame axes.
274 */
275 public Distance getDistanceZ() {
276 return new Distance(z, DistanceUnit.METER);
277 }
278
279 /**
280 * Sets cartesian z coordinate of body position resolved along ECEF-frame axes.
281 *
282 * @param z cartesian z coordinate of body position to be set.
283 */
284 public void setZ(final Distance z) {
285 this.z = convertDistance(z);
286 }
287
288 /**
289 * Sets cartesian coordinates of body position and resolved along ECEF-frame axes.
290 *
291 * @param x cartesian x coordinate of body position.
292 * @param y cartesian y coordinate of body position.
293 * @param z cartesian z coordinate of body position.
294 */
295 public void setCoordinates(final Distance x, final Distance y, final Distance z) {
296 setX(x);
297 setY(y);
298 setZ(z);
299 }
300
301 /**
302 * Gets norm of position expressed in meters (m), which represents the distance to
303 * Earth's center of mass.
304 *
305 * @return position norm expressed in meters (m).
306 */
307 public double getNorm() {
308 return Math.sqrt(x * x + y * y + z * z);
309 }
310
311 /**
312 * Gets norm of position, which represents the distance to Earth's center of mass.
313 *
314 * @param result instance where result will be stored.
315 */
316 public void getNormAsDistance(final Distance result) {
317 result.setValue(getNorm());
318 result.setUnit(DistanceUnit.METER);
319 }
320
321 /**
322 * Gets norm of position, which represents the distance to Earth's center of mass.
323 *
324 * @return position norm.
325 */
326 public Distance getNormAsDistance() {
327 return new Distance(getNorm(), DistanceUnit.METER);
328 }
329
330 /**
331 * Copies this instance data into provided instance.
332 *
333 * @param output destination instance where data will be copied to.
334 */
335 public void copyTo(final ECEFPosition output) {
336 output.x = x;
337 output.y = y;
338 output.z = z;
339 }
340
341 /**
342 * Copies data of provided instance into this instance.
343 *
344 * @param input instance to copy data from.
345 */
346 public void copyFrom(final ECEFPosition input) {
347 x = input.x;
348 y = input.y;
349 z = input.z;
350 }
351
352 /**
353 * Gets position coordinates expressed in meters (m) as an array.
354 *
355 * @param result array instance where position coordinates will
356 * be stored in x,y,z order.
357 * @throws IllegalArgumentException if provided array does not have length 3.
358 */
359 public void asArray(final double[] result) {
360 if (result.length != COMPONENTS) {
361 throw new IllegalArgumentException();
362 }
363
364 result[0] = x;
365 result[1] = y;
366 result[2] = z;
367 }
368
369 /**
370 * Gets position coordinates expressed in meters (m) as an array.
371 *
372 * @return array containing position coordinates in x,y,z order.
373 */
374 public double[] asArray() {
375 final var result = new double[COMPONENTS];
376 asArray(result);
377 return result;
378 }
379
380 /**
381 * Gets position coordinates expressed in meters (m) as a column matrix.
382 * If provided matrix does not have size 3x1, it will be resized.
383 *
384 * @param result matrix instance where gravity coordinates will be stored in
385 * x,y,z order.
386 */
387 @SuppressWarnings("DuplicatedCode")
388 public void asMatrix(final Matrix result) {
389 if (result.getRows() != COMPONENTS || result.getColumns() != 1) {
390 try {
391 result.resize(COMPONENTS, 1);
392 } catch (final WrongSizeException ignore) {
393 // never happens
394 }
395 }
396
397 result.setElementAtIndex(0, x);
398 result.setElementAtIndex(1, y);
399 result.setElementAtIndex(2, z);
400 }
401
402 /**
403 * Gets position coordinates expressed in meters (m) as a column matrix.
404 *
405 * @return position coordinates stored in x,y,z order.
406 */
407 public Matrix asMatrix() {
408 Matrix result;
409 try {
410 result = new Matrix(COMPONENTS, 1);
411 asMatrix(result);
412 } catch (final WrongSizeException ignore) {
413 // never happens
414 result = null;
415 }
416 return result;
417 }
418
419 /**
420 * Computes and returns hash code for this instance. Hash codes are almost unique
421 * values that are useful for fast classification and storage of objects in
422 * collections.
423 *
424 * @return Hash code.
425 */
426 @Override
427 public int hashCode() {
428 return Objects.hash(x, y, z);
429 }
430
431 /**
432 * Checks if provided object is an ECEFPosition having exactly the same contents
433 * as this instance.
434 *
435 * @param o Object to be compared.
436 * @return true if both objects are considered to be equal, false otherwise.
437 */
438 @Override
439 public boolean equals(Object o) {
440 if (this == o) {
441 return true;
442 }
443 if (o == null || getClass() != o.getClass()) {
444 return false;
445 }
446 final ECEFPosition other = (ECEFPosition) o;
447 return equals(other);
448 }
449
450 /**
451 * Checks if provided instance has exactly the same contents as this instance.
452 *
453 * @param other instance to be compared.
454 * @return true if both instances are considered to be equal, false otherwise.
455 */
456 public boolean equals(final ECEFPosition other) {
457 return equals(other, 0.0);
458 }
459
460 /**
461 * Checks if provided instance has contents similar to this instance up to provided
462 * threshold value.
463 *
464 * @param other instance to be compared.
465 * @param threshold maximum difference allowed between position coordinates.
466 * @return true if both instances are considered to be equal (up to provided
467 * threshold), false otherwise.
468 */
469 public boolean equals(final ECEFPosition other, final double threshold) {
470 if (other == null) {
471 return false;
472 }
473
474 return Math.abs(x - other.x) <= threshold
475 && Math.abs(y - other.y) <= threshold
476 && Math.abs(z - other.z) <= threshold;
477 }
478
479 /**
480 * Makes a copy of this instance.
481 *
482 * @return a copy of this instance.
483 * @throws CloneNotSupportedException if clone fails for some reason.
484 */
485 @Override
486 protected Object clone() throws CloneNotSupportedException {
487 final var result = (ECEFPosition) super.clone();
488 copyTo(result);
489 return result;
490 }
491
492 /**
493 * Converts distance instance into meters value.
494 *
495 * @param distance instance to be converted.
496 * @return converted value.
497 */
498 private double convertDistance(final Distance distance) {
499 return DistanceConverter.convert(distance.getValue().doubleValue(),
500 distance.getUnit(), DistanceUnit.METER);
501 }
502 }