View Javadoc
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.InvalidRotationMatrixException;
22  import com.irurueta.geometry.Point3D;
23  import com.irurueta.geometry.Rotation3D;
24  import com.irurueta.units.Distance;
25  import com.irurueta.units.DistanceConverter;
26  import com.irurueta.units.DistanceUnit;
27  import com.irurueta.units.Speed;
28  import com.irurueta.units.SpeedConverter;
29  import com.irurueta.units.SpeedUnit;
30  
31  import java.io.Serializable;
32  import java.util.Objects;
33  
34  /**
35   * Base class for ECI or ECEF frames containing common logic and data for such frames.
36   */
37  public abstract class ECIorECEFFrame<T extends ECIorECEFFrame<?>> implements Frame, Serializable {
38  
39      /**
40       * Number of coordinates representing position.
41       */
42      public static final int NUM_POSITION_COORDINATES = 3;
43  
44      /**
45       * Number of coordinates representing velocity.
46       */
47      public static final int NUM_VELOCITY_COORDINATES = 3;
48  
49      /**
50       * Cartesian x coordinate of body position expressed in meters (m) with respect ECI or ECEF frame, resolved along
51       * the corresponding frame axes.
52       */
53      double x;
54  
55      /**
56       * Cartesian y coordinate of body position expressed in meters (m) with respect ECI or ECEF frame, resolved along
57       * the corresponding frame axes.
58       */
59      double y;
60  
61      /**
62       * Cartesian z coordinate of body position expressed in meters (m) with respect ECI or ECEF frame, resolved along
63       * the corresponding frame axes.
64       */
65      double z;
66  
67      /**
68       * X coordinate of velocity of body frame expressed in meters per second (m/s) with respect ECI or ECEF frame,
69       * resolved along the corresponding frame axes.
70       */
71      double vx;
72  
73      /**
74       * Y coordinate of velocity of body frame expressed in meters per second (m/s) with respect ECI or ECEF frame,
75       * resolved along the corresponding frame axes.
76       */
77      double vy;
78  
79      /**
80       * Z coordinate of velocity of body frame expressed in meters per second (m/s) with respect ECI or ECEF frame,
81       * resolved along the corresponding frame axes.
82       */
83      double vz;
84  
85      /**
86       * Body to ECI frame coordinate transformation matrix.
87       */
88      CoordinateTransformation c;
89  
90      /**
91       * Actual type class
92       */
93      transient Class<T> clazz;
94  
95      /**
96       * Constructor.
97       */
98      ECIorECEFFrame(final Class<T> c) {
99          clazz = c;
100     }
101 
102     /**
103      * Constructor.
104      *
105      * @param c Body to ECI or ECEF coordinate transformation.
106      * @throws InvalidSourceAndDestinationFrameTypeException if source or destination frame types are invalid.
107      */
108     ECIorECEFFrame(final CoordinateTransformation c) throws InvalidSourceAndDestinationFrameTypeException {
109         setCoordinateTransformation(c);
110     }
111 
112     /**
113      * Gets cartesian x coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
114      *
115      * @return cartesian x coordinate of body position.
116      */
117     public double getX() {
118         return x;
119     }
120 
121     /**
122      * Sets cartesian x coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
123      *
124      * @param x cartesian x coordinate of body position.
125      */
126     public void setX(final double x) {
127         this.x = x;
128     }
129 
130     /**
131      * Gets cartesian y coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
132      *
133      * @return cartesian y coordinate of body position.
134      */
135     public double getY() {
136         return y;
137     }
138 
139     /**
140      * Sets cartesian y coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
141      *
142      * @param y cartesian y coordinate of body position.
143      */
144     public void setY(final double y) {
145         this.y = y;
146     }
147 
148     /**
149      * Gets cartesian z coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
150      *
151      * @return cartesian z coordinate of body position.
152      */
153     public double getZ() {
154         return z;
155     }
156 
157     /**
158      * Sets cartesian z coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
159      *
160      * @param z cartesian z coordinate of body position.
161      */
162     public void setZ(final double z) {
163         this.z = z;
164     }
165 
166     /**
167      * Sets cartesian coordinates of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
168      *
169      * @param x cartesian x coordinate of body position, resolved along ECI or ECEF-frame axes.
170      * @param y cartesian y coordinate of body position, resolved along ECI or ECEF-frame axes.
171      * @param z cartesian z coordinate of body position, resolved along ECI or ECEF-frame axes.
172      */
173     public void setCoordinates(final double x, final double y, final double z) {
174         this.x = x;
175         this.y = y;
176         this.z = z;
177     }
178 
179     /**
180      * Gets body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
181      *
182      * @return body position.
183      */
184     public Point3D getPosition() {
185         return new InhomogeneousPoint3D(x, y, z);
186     }
187 
188     /**
189      * Gets body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
190      *
191      * @param result instance where position data is copied to.
192      */
193     public void getPosition(final Point3D result) {
194         result.setInhomogeneousCoordinates(x, y, z);
195     }
196 
197     /**
198      * Sets body position expressed in meters (m) and resolved along ECI or ECEF-frame axes.
199      *
200      * @param point body position to be set.
201      */
202     public void setPosition(final Point3D point) {
203         x = point.getInhomX();
204         y = point.getInhomY();
205         z = point.getInhomZ();
206     }
207 
208     /**
209      * Gets cartesian x coordinate of body position resolved along ECI or ECEF-frame axes.
210      *
211      * @param result instance where cartesian x coordinate of body position will be stored.
212      */
213     public void getPositionX(final Distance result) {
214         result.setValue(x);
215         result.setUnit(DistanceUnit.METER);
216     }
217 
218     /**
219      * Gets cartesian x coordinate of body position resolved along ECI or ECEF-frame axes.
220      *
221      * @return x coordinate of body position resolved along ECI or ECEF-frame axes.
222      */
223     public Distance getPositionX() {
224         return new Distance(x, DistanceUnit.METER);
225     }
226 
227     /**
228      * Sets cartesian x coordinate of body position resolved along ECI or ECEF-frame axes.
229      *
230      * @param positionX cartesian x coordinate of body position to be set.
231      */
232     public void setPositionX(final Distance positionX) {
233         x = DistanceConverter.convert(positionX.getValue().doubleValue(), positionX.getUnit(), DistanceUnit.METER);
234     }
235 
236     /**
237      * Gets cartesian y coordinate of body position resolved along ECI or ECEF-frame axes.
238      *
239      * @param result instance where cartesian y coordinate of body position will be stored.
240      */
241     public void getPositionY(final Distance result) {
242         result.setValue(y);
243         result.setUnit(DistanceUnit.METER);
244     }
245 
246     /**
247      * Gets cartesian y coordinate of body position resolved along ECI or ECEF-frame axes.
248      *
249      * @return y coordinate of body position resolved along ECI or ECEF-frame axes.
250      */
251     public Distance getPositionY() {
252         return new Distance(y, DistanceUnit.METER);
253     }
254 
255     /**
256      * Sets cartesian y coordinate of body position resolved along ECI or ECEF-frame axes.
257      *
258      * @param positionY cartesian y coordinate of body position to be set.
259      */
260     public void setPositionY(final Distance positionY) {
261         y = DistanceConverter.convert(positionY.getValue().doubleValue(), positionY.getUnit(), DistanceUnit.METER);
262     }
263 
264     /**
265      * Gets cartesian z coordinate of body position resolved along ECI or ECEF-frame axes.
266      *
267      * @param result instance where cartesian z coordinate of body position will be stored.
268      */
269     public void getPositionZ(final Distance result) {
270         result.setValue(z);
271         result.setUnit(DistanceUnit.METER);
272     }
273 
274     /**
275      * Gets cartesian z coordinate of body position resolved along ECI or ECEF-frame axes.
276      *
277      * @return z coordinate of body position resolved along ECI or ECEF-frame axes.
278      */
279     public Distance getPositionZ() {
280         return new Distance(z, DistanceUnit.METER);
281     }
282 
283     /**
284      * Sets cartesian z coordinate of body position resolved along ECI or ECEF-frame axes.
285      *
286      * @param positionZ cartesian z coordinate of body position to be set.
287      */
288     public void setPositionZ(final Distance positionZ) {
289         z = DistanceConverter.convert(positionZ.getValue().doubleValue(), positionZ.getUnit(), DistanceUnit.METER);
290     }
291 
292     /**
293      * Sets cartesian coordinates of body position resolved along ECI or ECEF-frame axes.
294      *
295      * @param positionX cartesian x coordinate of body position to be set, resolved along ECI or ECEF-frame axes.
296      * @param positionY cartesian y coordinate of body position to be set, resolved along ECI or ECEF-frame axes.
297      * @param positionZ cartesian z coordinate of body position to be set, resolved along ECI or ECEF-frame axes.
298      */
299     public void setPositionCoordinates(final Distance positionX, final Distance positionY, final Distance positionZ) {
300         setPositionX(positionX);
301         setPositionY(positionY);
302         setPositionZ(positionZ);
303     }
304 
305     /**
306      * Gets norm of position expressed in meters (m), which represents the distance to
307      * Earth's center of mass.
308      *
309      * @return position norm expressed in meters (m).
310      */
311     public double getPositionNorm() {
312         return Math.sqrt(x * x + y * y + z * z);
313     }
314 
315     /**
316      * Gets norm of position, which represents the distance to Earth's center of mass.
317      *
318      * @param result instance where result will be stored.
319      */
320     public void getPositionNormAsDistance(final Distance result) {
321         result.setValue(getPositionNorm());
322         result.setUnit(DistanceUnit.METER);
323     }
324 
325     /**
326      * Gets norm of position, which represents the distance to Earth's center of mass.
327      *
328      * @return position norm.
329      */
330     public Distance getPositionNormAsDistance() {
331         return new Distance(getPositionNorm(), DistanceUnit.METER);
332     }
333 
334     /**
335      * Gets x coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or
336      * ECEF-frame axes.
337      *
338      * @return x coordinate of velocity.
339      */
340     public double getVx() {
341         return vx;
342     }
343 
344     /**
345      * Sets x coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or
346      * ECEF-frame axes.
347      *
348      * @param vx x coordinate of velocity.
349      */
350     public void setVx(final double vx) {
351         this.vx = vx;
352     }
353 
354     /**
355      * Gets y coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or
356      * ECEF-frame axes.
357      *
358      * @return y coordinate of velocity.
359      */
360     public double getVy() {
361         return vy;
362     }
363 
364     /**
365      * Sets y coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or
366      * ECEF-frame axes.
367      *
368      * @param vy y coordinate of velocity.
369      */
370     public void setVy(final double vy) {
371         this.vy = vy;
372     }
373 
374     /**
375      * Gets z coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or
376      * ECEF-frame axes.
377      *
378      * @return z coordinate of velocity.
379      */
380     public double getVz() {
381         return vz;
382     }
383 
384     /**
385      * Sets z coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or
386      * ECEF-frame axes.
387      *
388      * @param vz z coordinate of velocity.
389      */
390     public void setVz(final double vz) {
391         this.vz = vz;
392     }
393 
394     /**
395      * Sets velocity coordinates of body frame expressed in meters per second (m/s) resolved along ECI or
396      * ECEF-frame axes.
397      *
398      * @param vx x coordinate of velocity.
399      * @param vy y coordinate of velocity.
400      * @param vz z coordinate of velocity.
401      */
402     public void setVelocityCoordinates(final double vx, final double vy, final double vz) {
403         this.vx = vx;
404         this.vy = vy;
405         this.vz = vz;
406     }
407 
408     /**
409      * Gets norm of velocity expressed in meters per second (m/s), which represents
410      * the speed of the body.
411      *
412      * @return norm of velocity expressed in meters per second (m/s).
413      */
414     public double getVelocityNorm() {
415         return Math.sqrt(vx * vx + vy * vy + vz * vz);
416     }
417 
418     /**
419      * Gets norm of velocity, which represents the speed of the body.
420      *
421      * @param result velocity norm.
422      */
423     public void getVelocityNormAsSpeed(final Speed result) {
424         result.setValue(getVelocityNorm());
425         result.setUnit(SpeedUnit.METERS_PER_SECOND);
426     }
427 
428     /**
429      * Gets norm of velocity, which represents the speed of the body.
430      *
431      * @return velocity norm.
432      */
433     public Speed getVelocityNormAsSpeed() {
434         return new Speed(getVelocityNorm(), SpeedUnit.METERS_PER_SECOND);
435     }
436 
437     /**
438      * Gets x coordinate of velocity of body frame resolved along ECEF-frame axes.
439      *
440      * @param result instance where x coordinate of velocity will be stored.
441      */
442     public void getSpeedX(final Speed result) {
443         result.setValue(vx);
444         result.setUnit(SpeedUnit.METERS_PER_SECOND);
445     }
446 
447     /**
448      * Gets x coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
449      *
450      * @return x coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
451      */
452     public Speed getSpeedX() {
453         return new Speed(vx, SpeedUnit.METERS_PER_SECOND);
454     }
455 
456     /**
457      * Sets x coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
458      *
459      * @param speedX x coordinate of velocity of body frame resolved along ECI or ECEF-frame
460      *               axes to be set.
461      */
462     public void setSpeedX(final Speed speedX) {
463         vx = SpeedConverter.convert(speedX.getValue().doubleValue(), speedX.getUnit(), SpeedUnit.METERS_PER_SECOND);
464     }
465 
466     /**
467      * Gets y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
468      *
469      * @param result instance where y coordinate of velocity will be stored.
470      */
471     public void getSpeedY(final Speed result) {
472         result.setValue(vy);
473         result.setUnit(SpeedUnit.METERS_PER_SECOND);
474     }
475 
476     /**
477      * Gets y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
478      *
479      * @return y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
480      */
481     public Speed getSpeedY() {
482         return new Speed(vy, SpeedUnit.METERS_PER_SECOND);
483     }
484 
485     /**
486      * Sets y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
487      *
488      * @param speedY y coordinate of velocity of body frame resolved along ECI or ECEF-frame
489      *               axes to be set.
490      */
491     public void setSpeedY(final Speed speedY) {
492         vy = SpeedConverter.convert(speedY.getValue().doubleValue(), speedY.getUnit(), SpeedUnit.METERS_PER_SECOND);
493     }
494 
495     /**
496      * Gets z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
497      *
498      * @param result instance where z coordinate of velocity will be stored.
499      */
500     public void getSpeedZ(final Speed result) {
501         result.setValue(vz);
502         result.setUnit(SpeedUnit.METERS_PER_SECOND);
503     }
504 
505     /**
506      * Gets z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
507      *
508      * @return z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
509      */
510     public Speed getSpeedZ() {
511         return new Speed(vz, SpeedUnit.METERS_PER_SECOND);
512     }
513 
514     /**
515      * Sets z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes.
516      *
517      * @param speedZ z coordinate of velocity of body frame resolved along ECI or ECEF-frame
518      *               axes to be set.
519      */
520     public void setSpeedZ(final Speed speedZ) {
521         vz = SpeedConverter.convert(speedZ.getValue().doubleValue(), speedZ.getUnit(), SpeedUnit.METERS_PER_SECOND);
522     }
523 
524     /**
525      * Sets velocity coordinates of body frame resolved along ECI or ECEF-frame axes.
526      *
527      * @param speedX x coordinate of velocity to be set.
528      * @param speedY y coordinate of velocity to be set.
529      * @param speedZ z coordinate of velocity to be set.
530      */
531     public void setSpeedCoordinates(final Speed speedX, final Speed speedY, final Speed speedZ) {
532         setSpeedX(speedX);
533         setSpeedY(speedY);
534         setSpeedZ(speedZ);
535     }
536 
537     /**
538      * Gets coordinate transformation matrix.
539      * This is equivalent to calling getCoordinateTransformation(), but more efficient
540      *
541      * @return coordinate transformation matrix.
542      */
543     @Override
544     public Matrix getCoordinateTransformationMatrix() {
545         Matrix result;
546         try {
547             result = new Matrix(CoordinateTransformation.ROWS, CoordinateTransformation.COLS);
548             getCoordinateTransformationMatrix(result);
549         } catch (final WrongSizeException ignore) {
550             // never happens
551             result = null;
552         }
553         return result;
554     }
555 
556     /**
557      * Gets coordinate transformation matrix.
558      * This is equivalent to calling getCoordinateTransformation().getMatrix(), but more efficient
559      *
560      * @param result instance where coordinate transformation matrix will be copied to.
561      */
562     @Override
563     public void getCoordinateTransformationMatrix(final Matrix result) {
564         c.matrix.copyTo(result);
565     }
566 
567     /**
568      * Sets coordinate transformation matrix keeping current source and destination {@link FrameType}.
569      * This is more efficient than getting a copy of coordinate transformation calling to
570      * {@link #getCoordinateTransformation()}, setting coordinate matrix into copied coordinate transformation and
571      * then setting the coordinate transformation calling {@link #setCoordinateTransformation(CoordinateTransformation)}.
572      *
573      * @param matrix    a 3x3 coordinate transformation matrix to be set.
574      * @param threshold threshold to validate rotation matrix.
575      * @throws InvalidRotationMatrixException if provided matrix is not a valid rotation matrix (3x3 and orthonormal).
576      * @throws IllegalArgumentException       if provided threshold is negative.
577      */
578     @Override
579     public void setCoordinateTransformationMatrix(final Matrix matrix, final double threshold)
580             throws InvalidRotationMatrixException {
581         c.setMatrix(matrix,threshold);
582     }
583 
584     /**
585      * Sts coordinate transformation matrix keeping current source and destination {@link FrameType}.
586      * This is more efficient than getting a copy of coordinate transformation calling to
587      * {@link #getCoordinateTransformation()}, setting coordinate matrix into copied coordinate transformation and
588      * then setting the coordinate transformation calling {@link #setCoordinateTransformation(CoordinateTransformation)}.
589      *
590      * @param matrix a 3x3 coordinate transformation matrix to be set.
591      * @throws InvalidRotationMatrixException if provided matrix is not a valid rotation matrix (3x3 and orthonormal).
592      */
593     @Override
594     public void setCoordinateTransformationMatrix(final Matrix matrix) throws InvalidRotationMatrixException {
595         c.setMatrix(matrix);
596     }
597 
598     /**
599      * Gets coordinate transformation as a new 3D rotation instance.
600      * This is equivalent to calling getCoordinateTransformation().asRotation(), but more efficient.
601      *
602      * @return new coordinate transformation as a 3D rotation.
603      * @throws InvalidRotationMatrixException if internal matrix cannot be converted to a 3D rotation.
604      */
605     @Override
606     public Rotation3D getCoordinateTransformationRotation() throws InvalidRotationMatrixException {
607         return c.asRotation();
608     }
609 
610     /**
611      * Gets coordinate transformation as a 3D rotation.
612      * This is equivalent to calling getCoordinateTransformation().asRotation(), but more efficient.
613      *
614      * @param result instance where coordinate transformation 3D rotation will be copied to.
615      * @throws InvalidRotationMatrixException if internal matrix cannot be converted to a 3D rotation.
616      */
617     @Override
618     public void getCoordinateTransformationRotation(final Rotation3D result) throws InvalidRotationMatrixException {
619         c.asRotation(result);
620     }
621 
622     /**
623      * Sets coordinate transformation from 3D rotation and keeping current source and destination {@link FrameType}.
624      * This is more efficient than getting a copy of coordinate transformation calling to
625      * {@link #getCoordinateTransformation()}, setting rotation into copied coordinate transformation and
626      * then setting the coordinate transformation calling {@link #setCoordinateTransformation(CoordinateTransformation)}.
627      *
628      * @param rotation set rotation into current coordinate rotation.
629      */
630     @Override
631     public void setCoordinateTransformationRotation(final Rotation3D rotation) {
632         c.fromRotation(rotation);
633     }
634 
635     /**
636      * Copies this instance data into provided instance.
637      *
638      * @param output destination instance where data will be copied to.
639      */
640     public void copyTo(final T output) {
641         output.x = x;
642         output.y = y;
643         output.z = z;
644 
645         output.vx = vx;
646         output.vy = vy;
647         output.vz = vz;
648 
649         c.copyTo(output.c);
650     }
651 
652     /**
653      * Copies data of provided instance into this instance.
654      *
655      * @param input instance to copy data from.
656      */
657     public void copyFrom(final T input) {
658         x = input.x;
659         y = input.y;
660         z = input.z;
661 
662         vx = input.vx;
663         vy = input.vy;
664         vz = input.vz;
665 
666         c.copyFrom(input.c);
667     }
668 
669     /**
670      * Computes and returns hash code for this instance. Hash codes are almost unique
671      * values that are useful for fast classification and storage of objects in collections.
672      *
673      * @return Hash code.
674      */
675     @Override
676     public int hashCode() {
677         return Objects.hash(x, y, z, vx, vy, vz, c);
678     }
679 
680     /**
681      * Checks if provided instance has exactly the same contents as this instance.
682      *
683      * @param obj instance to be compared.
684      * @return true if both instances are considered to be equal, false otherwise.
685      */
686     @Override
687     public boolean equals(final Object obj) {
688         if (obj == null) {
689             return false;
690         }
691         if (obj == this) {
692             return true;
693         }
694         if (!clazz.isInstance(obj)) {
695             return false;
696         }
697 
698         //noinspection unchecked
699         final T other = (T) obj;
700         return equals(other, 0.0);
701     }
702 
703     /**
704      * Checks if provided instance has contents similar to this instance up to provided
705      * threshold value.
706      *
707      * @param other     instance to be compared.
708      * @param threshold maximum difference allowed between position, velocity and coordinate transformation matrix.
709      * @return true if both instances are considered to be equal (up to provided threshold), false otherwise.
710      */
711     public boolean equals(final T other, final double threshold) {
712         if (other == null) {
713             return false;
714         }
715 
716         return Math.abs(x - other.x) <= threshold
717                 && Math.abs(y - other.y) <= threshold
718                 && Math.abs(z - other.z) <= threshold
719                 && Math.abs(vx - other.vx) <= threshold
720                 && Math.abs(vy - other.vy) <= threshold
721                 && Math.abs(vz - other.vz) <= threshold
722                 && c.equals(other.c, threshold);
723     }
724 }