1   /* Copyright 2002-2025 CS GROUP
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.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.Rotation;
21  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.util.FastMath;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.Test;
26  import org.orekit.errors.OrekitException;
27  import org.orekit.errors.OrekitMessages;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.time.FieldAbsoluteDate;
30  import org.orekit.utils.AngularDerivativesFilter;
31  import org.orekit.utils.CartesianDerivativesFilter;
32  
33  
34  public class ShiftingTransformProviderTest {
35  
36      @Test
37      public void testCacheHitForward() {
38  
39          AbsoluteDate t0 = AbsoluteDate.GALILEO_EPOCH;
40          CirclingProvider referenceProvider = new CirclingProvider(t0, 0.2);
41          CirclingProvider rawProvider = new CirclingProvider(t0, 0.2);
42          ShiftingTransformProvider shiftingProvider =
43                  new ShiftingTransformProvider(rawProvider,
44                                                CartesianDerivativesFilter.USE_PVA,
45                                                AngularDerivativesFilter.USE_RRA,
46                                                5, 0.8, 10, 60.0, 60.0);
47          Assertions.assertEquals(5,   shiftingProvider.getGridPoints());
48          Assertions.assertEquals(0.8, shiftingProvider.getStep(), 1.0e-15);
49  
50          for (double dt = 0.8; dt <= 1.0; dt += 0.001) {
51              Transform reference = referenceProvider.getTransform(t0.shiftedBy(dt));
52              Transform interpolated = shiftingProvider.getTransform(t0.shiftedBy(dt));
53              Transform error = new Transform(reference.getDate(), reference, interpolated.getInverse());
54  
55              Assertions.assertEquals(0.0, error.getCartesian().getPosition().getNorm(),           1.1e-5);
56              Assertions.assertEquals(0.0, error.getCartesian().getVelocity().getNorm(),           1.6e-4);
57              Assertions.assertEquals(0.0, error.getCartesian().getAcceleration().getNorm(),       1.6e-3);
58              Assertions.assertEquals(0.0, error.getAngular().getRotation().getAngle(),            4.2e-16);
59              Assertions.assertEquals(0.0, error.getAngular().getRotationRate().getNorm(),         1.2e-16);
60              Assertions.assertEquals(0.0, error.getAngular().getRotationAcceleration().getNorm(), 7.1e-30);
61  
62              StaticTransform staticError = StaticTransform.compose(
63                      reference.getDate(),
64                      reference,
65                      shiftingProvider.getStaticTransform(t0.shiftedBy(dt)).getInverse());
66              Assertions.assertEquals(0.0, staticError.getTranslation().getNorm(), 1.1e-5);
67              Assertions.assertEquals(0.0, staticError.getRotation().getAngle(),   4.2e-16);
68          }
69          Assertions.assertEquals(8,   rawProvider.getCount());
70          Assertions.assertEquals(200, referenceProvider.getCount());
71  
72      }
73  
74      @Test
75      public void testCacheHitBackward() {
76  
77          AbsoluteDate t0 = AbsoluteDate.GALILEO_EPOCH;
78          CirclingProvider referenceProvider = new CirclingProvider(t0, 0.2);
79          CirclingProvider rawProvider = new CirclingProvider(t0, 0.2);
80          ShiftingTransformProvider shiftingProvider =
81                  new ShiftingTransformProvider(rawProvider,
82                                                CartesianDerivativesFilter.USE_PVA,
83                                                AngularDerivativesFilter.USE_RRA,
84                                                5, 0.8, 10, 60.0, 60.0);
85          Assertions.assertEquals(5,   shiftingProvider.getGridPoints());
86          Assertions.assertEquals(0.8, shiftingProvider.getStep(), 1.0e-15);
87  
88          for (double dt = 1.0; dt >= 0.8; dt -= 0.001) {
89              Transform reference = referenceProvider.getTransform(t0.shiftedBy(dt));
90              Transform interpolated = shiftingProvider.getTransform(t0.shiftedBy(dt));
91              Transform error = new Transform(reference.getDate(), reference, interpolated.getInverse());
92  
93              Assertions.assertEquals(0.0, error.getCartesian().getPosition().getNorm(),           1.1e-5);
94              Assertions.assertEquals(0.0, error.getCartesian().getVelocity().getNorm(),           1.6e-4);
95              Assertions.assertEquals(0.0, error.getCartesian().getAcceleration().getNorm(),       1.6e-3);
96              Assertions.assertEquals(0.0, error.getAngular().getRotation().getAngle(),            4.2e-16);
97              Assertions.assertEquals(0.0, error.getAngular().getRotationRate().getNorm(),         2.3e-16);
98              Assertions.assertEquals(0.0, error.getAngular().getRotationAcceleration().getNorm(), 7.1e-30);
99  
100             StaticTransform staticError = StaticTransform.compose(
101                     reference.getDate(),
102                     reference,
103                     shiftingProvider.getStaticTransform(t0.shiftedBy(dt)).getInverse());
104             Assertions.assertEquals(0.0, staticError.getTranslation().getNorm(), 1.1e-5);
105             Assertions.assertEquals(0.0, staticError.getRotation().getAngle(),   4.2e-16);
106         }
107         Assertions.assertEquals(10,   rawProvider.getCount());
108         Assertions.assertEquals(200, referenceProvider.getCount());
109 
110     }
111 
112     @Test
113     public void testForwardException() {
114         Assertions.assertThrows(OrekitException.class, () -> {
115             ShiftingTransformProvider shiftingProvider =
116                     new ShiftingTransformProvider(new TransformProvider() {
117                         public Transform getTransform(AbsoluteDate date) {
118                             throw new OrekitException(OrekitMessages.INTERNAL_ERROR);
119                         }
120                         public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
121                             throw new UnsupportedOperationException("never called in this test");
122                         }
123                     },
124                             CartesianDerivativesFilter.USE_PVA,
125                             AngularDerivativesFilter.USE_RRA,
126                             5, 0.8, 10, 60.0, 60.0);
127             shiftingProvider.getTransform(AbsoluteDate.J2000_EPOCH);
128         });
129     }
130 
131     private static class CirclingProvider implements TransformProvider {
132 
133         private int count;
134         private final AbsoluteDate t0;
135         private final double omega;
136 
137         public CirclingProvider(final AbsoluteDate t0, final double omega) {
138             this.count = 0;
139             this.t0    = t0;
140             this.omega = omega;
141         }
142 
143         public Transform getTransform(final AbsoluteDate date) {
144             // the following transform corresponds to a frame moving along the circle r = 1
145             // with its x axis always pointing to the reference frame center
146             ++count;
147             final double dt = date.durationFrom(t0);
148             final double cos = FastMath.cos(omega * dt);
149             final double sin = FastMath.sin(omega * dt);
150             return new Transform(date,
151                                  new Transform(date,
152                                                new Vector3D(-cos, -sin, 0),
153                                                new Vector3D(omega * sin, -omega * cos, 0),
154                                                new Vector3D(omega * omega * cos, omega * omega * sin, 0)),
155                                  new Transform(date,
156                                                new Rotation(Vector3D.PLUS_K,
157                                                             FastMath.PI - omega * dt,
158                                                             RotationConvention.VECTOR_OPERATOR),
159                                                new Vector3D(omega, Vector3D.PLUS_K)));
160         }
161 
162         public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
163             throw new UnsupportedOperationException("never called in this test");
164         }
165 
166         public int getCount() {
167             return count;
168         }
169 
170         private Object readResolve() {
171             count = 0;
172             return this;
173         }
174     }
175 
176 }