1   /* Copyright 2002-2022 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  
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.geometry.euclidean.threed.Rotation;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.random.RandomGenerator;
24  import org.hipparchus.random.Well19937a;
25  import org.hipparchus.util.Decimal64;
26  import org.hipparchus.util.Decimal64Field;
27  import org.hipparchus.util.FastMath;
28  import org.junit.Assert;
29  import org.junit.Test;
30  import org.orekit.time.AbsoluteDate;
31  import org.orekit.time.FieldAbsoluteDate;
32  import org.orekit.utils.PVCoordinates;
33  
34  public class TransformProviderUtilTest {
35  
36      @Test
37      public void testIdentity() {
38          RandomGenerator random = new Well19937a(0x87c3a5c51fb0235el);
39          final AbsoluteDate date = AbsoluteDate.J2000_EPOCH;
40          checkNoTransform(TransformProviderUtils.IDENTITY_PROVIDER.getTransform(date), random);
41      }
42  
43      @Test
44      public void testIdentityField() {
45          RandomGenerator random = new Well19937a(0x7086a8e4ad1265b0l);
46          final FieldAbsoluteDate<Decimal64> date = new FieldAbsoluteDate<>(Decimal64Field.getInstance(),
47                                                                            AbsoluteDate.J2000_EPOCH);
48          checkNoTransform(TransformProviderUtils.IDENTITY_PROVIDER.getTransform(date), random);
49      }
50  
51      @Test
52      public void testReverse() {
53          RandomGenerator random = new Well19937a(0xba49d4909717ec6cl);
54          final AbsoluteDate date = AbsoluteDate.J2000_EPOCH;
55          for (int i = 0; i < 20; ++i) {
56              TransformProvider tp = constantProvider(random);
57              TransformProvider reversed = TransformProviderUtils.getReversedProvider(tp);
58              checkNoTransform(new Transform(date, tp.getTransform(date), reversed.getTransform(date)), random);
59              checkNoTransform(new Transform(date, reversed.getTransform(date), tp.getTransform(date)), random);
60          }
61      }
62  
63      @Test
64      public void testReverseField() {
65          RandomGenerator random = new Well19937a(0xd74443b3079403e7l);
66          final FieldAbsoluteDate<Decimal64> date = new FieldAbsoluteDate<>(Decimal64Field.getInstance(),
67                                                                            AbsoluteDate.J2000_EPOCH);
68          for (int i = 0; i < 20; ++i) {
69              TransformProvider tp = constantProvider(random);
70              TransformProvider reversed = TransformProviderUtils.getReversedProvider(tp);
71              checkNoTransform(new FieldTransform<>(date, tp.getTransform(date), reversed.getTransform(date)), random);
72              checkNoTransform(new FieldTransform<>(date, reversed.getTransform(date), tp.getTransform(date)), random);
73          }
74      }
75  
76      @Test
77      public void testCombine() {
78          RandomGenerator random = new Well19937a(0x6e3b2c793680e7e3l);
79          final AbsoluteDate date = AbsoluteDate.J2000_EPOCH;
80          for (int i = 0; i < 20; ++i) {
81              TransformProvider first  = constantProvider(random);
82              TransformProvider second = constantProvider(random);
83              TransformProvider combined = TransformProviderUtils.getCombinedProvider(first, second);
84              checkNoTransform(new Transform(date,
85                                             new Transform(date, first.getTransform(date), second.getTransform(date)).getInverse(),
86                                             combined.getTransform(date)),
87                               random);
88          }
89      }
90  
91      @Test
92      public void testCombineField() {
93          RandomGenerator random = new Well19937a(0x1f8bf20bfa4b54eal);
94          final FieldAbsoluteDate<Decimal64> date = new FieldAbsoluteDate<>(Decimal64Field.getInstance(),
95                                                                            AbsoluteDate.J2000_EPOCH);
96          for (int i = 0; i < 20; ++i) {
97              TransformProvider first  = constantProvider(random);
98              TransformProvider second = constantProvider(random);
99              TransformProvider combined = TransformProviderUtils.getCombinedProvider(first, second);
100             checkNoTransform(new FieldTransform<>(date,
101                                                   new FieldTransform<>(date, first.getTransform(date), second.getTransform(date)).getInverse(),
102                                                   combined.getTransform(date)),
103                              random);
104         }
105     }
106 
107     private TransformProvider constantProvider(RandomGenerator random) {
108         final Transform combined = randomTransform(random);
109         return new TransformProvider() {
110             private static final long serialVersionUID = 20180330L;
111             public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(FieldAbsoluteDate<T> date)
112                 {
113                 return new FieldTransform<>(date.getField(), combined);
114             }
115             public Transform getTransform(AbsoluteDate date)
116                 {
117                 return combined;
118             }
119         };
120     }
121 
122     private Transform randomTransform(RandomGenerator random) {
123         // generate a random transform
124         Transform combined = Transform.IDENTITY;
125         for (int k = 0; k < 20; ++k) {
126             Transform t = random.nextBoolean() ?
127                           new Transform(AbsoluteDate.J2000_EPOCH, randomVector(1.0e3, random), randomVector(1.0, random), randomVector(1.0e-3, random)) :
128                           new Transform(AbsoluteDate.J2000_EPOCH, randomRotation(random), randomVector(0.01, random), randomVector(1.0e-4, random));
129             combined = new Transform(AbsoluteDate.J2000_EPOCH, combined, t);
130         }
131         return combined;
132     }
133 
134     private Vector3D randomVector(double scale, RandomGenerator random) {
135         return new Vector3D(random.nextDouble() * scale,
136                             random.nextDouble() * scale,
137                             random.nextDouble() * scale);
138     }
139 
140     private Rotation randomRotation(RandomGenerator random) {
141         double q0 = random.nextDouble() * 2 - 1;
142         double q1 = random.nextDouble() * 2 - 1;
143         double q2 = random.nextDouble() * 2 - 1;
144         double q3 = random.nextDouble() * 2 - 1;
145         double q  = FastMath.sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
146         return new Rotation(q0 / q, q1 / q, q2 / q, q3 / q, false);
147     }
148 
149     private void checkNoTransform(FieldTransform<Decimal64> transform, RandomGenerator random) {
150         for (int i = 0; i < 100; ++i) {
151             Vector3D a = randomVector(1.0e3, random);
152             Vector3D tA = transform.transformVector(a).toVector3D();
153             Assert.assertEquals(0, a.subtract(tA).getNorm(), 1.0e-10 * a.getNorm());
154             Vector3D b = randomVector(1.0e3, random);
155             Vector3D tB = transform.transformPosition(b).toVector3D();
156             Assert.assertEquals(0, b.subtract(tB).getNorm(), 1.0e-10 * b.getNorm());
157             PVCoordinates pv  = new PVCoordinates(randomVector(1.0e3, random), randomVector(1.0, random), randomVector(1.0e-3, random));
158             PVCoordinates tPv = transform.transformPVCoordinates(pv).toPVCoordinates();
159             checkVector(pv.getPosition(),     tPv.getPosition(), 1.0e-10);
160             checkVector(pv.getVelocity(),     tPv.getVelocity(), 3.0e-9);
161             checkVector(pv.getAcceleration(), tPv.getAcceleration(), 3.0e-9);
162         }
163     }
164 
165     private void checkNoTransform(Transform transform, RandomGenerator random) {
166         for (int i = 0; i < 100; ++i) {
167             Vector3D a = randomVector(1.0e3, random);
168             Vector3D tA = transform.transformVector(a);
169             Assert.assertEquals(0, a.subtract(tA).getNorm(), 1.0e-10 * a.getNorm());
170             Vector3D b = randomVector(1.0e3, random);
171             Vector3D tB = transform.transformPosition(b);
172             Assert.assertEquals(0, b.subtract(tB).getNorm(), 1.0e-10 * b.getNorm());
173             PVCoordinates pv  = new PVCoordinates(randomVector(1.0e3, random), randomVector(1.0, random), randomVector(1.0e-3, random));
174             PVCoordinates tPv = transform.transformPVCoordinates(pv);
175             checkVector(pv.getPosition(),     tPv.getPosition(), 1.0e-10);
176             checkVector(pv.getVelocity(),     tPv.getVelocity(), 3.0e-9);
177             checkVector(pv.getAcceleration(), tPv.getAcceleration(), 3.0e-9);
178         }
179     }
180 
181     private void checkVector(Vector3D reference, Vector3D result, double relativeTolerance) {
182         double refNorm = reference.getNorm();
183         double resNorm = result.getNorm();
184         double tolerance = relativeTolerance * (1 + FastMath.max(refNorm, resNorm));
185         Assert.assertEquals("ref = " + reference + ", res = " + result + " -> " +
186                             (Vector3D.distance(reference, result) / (1 + FastMath.max(refNorm, resNorm))),
187                             0, Vector3D.distance(reference, result), tolerance);
188     }
189 
190 }