1   /* Copyright 2022-2025 Romain Serra
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.frames;
18  
19  import org.hipparchus.Field;
20  import org.hipparchus.complex.Complex;
21  import org.hipparchus.complex.ComplexField;
22  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Rotation;
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.Test;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.time.FieldAbsoluteDate;
30  import org.orekit.utils.FieldPVCoordinates;
31  import org.orekit.utils.PVCoordinates;
32  import org.orekit.utils.TimeStampedFieldPVCoordinates;
33  
34  class FieldKinematicTransformTest {
35  
36      @Test
37      void testOf() {
38          // GIVEN
39          final KinematicTransform kinematicTransform = createArbitraryKineticTransform();
40          // WHEn
41          final FieldKinematicTransform<Complex> fieldKinematicTransform = FieldKinematicTransform.of(ComplexField.getInstance(),
42                  kinematicTransform);
43          // THEN
44          Assertions.assertEquals(fieldKinematicTransform.getDate(), kinematicTransform.getDate());
45          Assertions.assertEquals(fieldKinematicTransform.getTranslation().toVector3D(), kinematicTransform.getTranslation());
46          Assertions.assertEquals(fieldKinematicTransform.getVelocity().toVector3D(), kinematicTransform.getVelocity());
47          Assertions.assertEquals(0., Rotation.distance(fieldKinematicTransform.getRotation().toRotation(),
48                  kinematicTransform.getRotation()));
49          Assertions.assertEquals(fieldKinematicTransform.getRotationRate().toVector3D(),
50                  kinematicTransform.getRotationRate());
51      }
52  
53      private KinematicTransform createArbitraryKineticTransform() {
54          return KinematicTransform.of(AbsoluteDate.ARBITRARY_EPOCH,
55                  new PVCoordinates(Vector3D.MINUS_I, Vector3D.PLUS_J),
56                  new Rotation(Vector3D.MINUS_K, Vector3D.PLUS_I),
57                  Vector3D.MINUS_J);
58      }
59  
60      @Test
61      void testGetInverse() {
62          // GIVEN
63          final FieldKinematicTransform<Complex> fieldKinematicTransform = createArbitraryFieldKineticTransform();
64          // WHEn
65          final FieldKinematicTransform<Complex> fieldInverse = fieldKinematicTransform.getInverse();
66          // THEN
67          final KinematicTransform kinematicTransform = createKinematicTransform(fieldKinematicTransform);
68          final KinematicTransform inverse = kinematicTransform.getInverse();
69          Assertions.assertEquals(inverse.getDate(), fieldInverse.getDate());
70          Assertions.assertEquals(inverse.getTranslation(), fieldInverse.getTranslation().toVector3D());
71          Assertions.assertEquals(inverse.getVelocity(), fieldInverse.getVelocity().toVector3D());
72          Assertions.assertEquals(0., Rotation.distance(inverse.getRotation(),
73                  fieldInverse.getRotation().toRotation()));
74          Assertions.assertEquals(inverse.getRotationRate(), fieldInverse.getRotationRate().toVector3D());
75      }
76  
77      @Test
78      void testCompositeVelocity() {
79          // GIVEN
80          final FieldKinematicTransform<Complex> fieldKinematicTransform = createArbitraryFieldKineticTransform();
81          final Field<Complex> field = fieldKinematicTransform.getFieldDate().getField();
82          // WHEN
83          final FieldVector3D<Complex> actualCompositeVelocity = FieldKinematicTransform
84                  .compositeVelocity(fieldKinematicTransform, FieldKinematicTransform.getIdentity(field));
85          // THEN
86          final KinematicTransform kinematicTransform = createKinematicTransform(fieldKinematicTransform);
87          final Vector3D expectedCompositeVelocity = kinematicTransform.getVelocity();
88          Assertions.assertEquals(expectedCompositeVelocity, actualCompositeVelocity.toVector3D());
89      }
90  
91      @Test
92      void testCompositeRotationRate() {
93          // GIVEN
94          final FieldKinematicTransform<Complex> fieldKinematicTransform = createArbitraryFieldKineticTransform();
95          final Field<Complex> field = fieldKinematicTransform.getFieldDate().getField();
96          // WHEN
97          final FieldVector3D<Complex> actualCompositeRotationRate = FieldKinematicTransform
98                  .compositeRotationRate(fieldKinematicTransform, FieldKinematicTransform.getIdentity(field));
99          // THEN
100         final KinematicTransform kinematicTransform = createKinematicTransform(fieldKinematicTransform);
101         final Vector3D expectedCompositeRotationRate = kinematicTransform.getRotationRate();
102         Assertions.assertEquals(expectedCompositeRotationRate, actualCompositeRotationRate.toVector3D());
103     }
104 
105     @Test
106     void testTransformPVOnly(){
107         // GIVEN
108         final FieldKinematicTransform<Complex> fieldKinematicTransform = createArbitraryFieldKineticTransform();
109         final FieldPVCoordinates<Complex> pvCoordinates = createFieldPV();
110         // WHEN
111         final FieldPVCoordinates<Complex> convertedPV = fieldKinematicTransform.transformOnlyPV(pvCoordinates);
112         // THEN
113         final KinematicTransform kinematicTransform = createKinematicTransform(fieldKinematicTransform);
114         final PVCoordinates expectedPV = kinematicTransform.transformOnlyPV(pvCoordinates
115                 .toPVCoordinates());
116         comparePVCoordinates(expectedPV, convertedPV.toPVCoordinates());
117     }
118 
119     @Test
120     void testTransformTimeStampedPVCoordinatesWithoutA() {
121         // GIVEN
122         final FieldKinematicTransform<Complex> fieldKinematicTransform = createArbitraryFieldKineticTransform();
123         final TimeStampedFieldPVCoordinates<Complex> pvCoordinates = new TimeStampedFieldPVCoordinates<>(AbsoluteDate.ARBITRARY_EPOCH,
124                 createFieldPV());
125         // WHEN
126         final TimeStampedFieldPVCoordinates<Complex> convertedPV = fieldKinematicTransform
127                 .transformOnlyPV(pvCoordinates);
128         // THEN
129         final KinematicTransform kinematicTransform = createKinematicTransform(fieldKinematicTransform);
130         final PVCoordinates expectedPV = kinematicTransform.transformOnlyPV(pvCoordinates
131                 .toPVCoordinates());
132         comparePVCoordinates(expectedPV, convertedPV.toPVCoordinates());
133     }
134 
135     private FieldPVCoordinates<Complex> createFieldPV() {
136         final PVCoordinates pvCoordinates = new PVCoordinates(new Vector3D(1, 2, 3), new Vector3D(4, 5, 6));
137         return new FieldPVCoordinates<>(ComplexField.getInstance(), pvCoordinates);
138     }
139 
140     private void comparePVCoordinates(final PVCoordinates pvCoordinates, final PVCoordinates reconvertedPV) {
141         final double tolerance = 1e-10;
142         final double[] expectedPosition = pvCoordinates.getPosition().toArray();
143         final double[] actualPosition = reconvertedPV.getPosition().toArray();
144         final double[] expectedVelocity = pvCoordinates.getVelocity().toArray();
145         final double[] actualVelocity = reconvertedPV.getVelocity().toArray();
146         for (int i = 0; i < 3; i++) {
147             Assertions.assertEquals(expectedPosition[i], actualPosition[i], tolerance);
148             Assertions.assertEquals(expectedVelocity[i], actualVelocity[i], tolerance);
149         }
150     }
151 
152     private FieldKinematicTransform<Complex> createArbitraryFieldKineticTransform() {
153         final Field<Complex> complexField = ComplexField.getInstance();
154         final FieldAbsoluteDate<Complex> fieldAbsoluteDate = new FieldAbsoluteDate<>(complexField,
155                 AbsoluteDate.ARBITRARY_EPOCH);
156         return FieldKinematicTransform.of(fieldAbsoluteDate,
157                 new FieldPVCoordinates<>(complexField, new PVCoordinates(Vector3D.MINUS_I, Vector3D.PLUS_J)),
158                 new FieldRotation<>(complexField, new Rotation(Vector3D.MINUS_K, Vector3D.PLUS_I)),
159                 new FieldVector3D<>(complexField, Vector3D.MINUS_J));
160     }
161 
162     private KinematicTransform createKinematicTransform(final FieldKinematicTransform<?> fieldKinematicTransform) {
163         return KinematicTransform.of(fieldKinematicTransform.getDate(),
164                 new PVCoordinates(fieldKinematicTransform.getTranslation().toVector3D(),
165                 fieldKinematicTransform.getVelocity().toVector3D()),
166                 fieldKinematicTransform.getRotation().toRotation(),
167                 fieldKinematicTransform.getRotationRate().toVector3D());
168     }
169 
170 }