View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF 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    *      https://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  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.geometry.euclidean.threed;
24  
25  import org.hipparchus.analysis.differentiation.DSFactory;
26  import org.hipparchus.analysis.differentiation.DerivativeStructure;
27  import org.hipparchus.exception.MathIllegalArgumentException;
28  import org.hipparchus.exception.MathIllegalStateException;
29  import org.hipparchus.exception.MathRuntimeException;
30  import org.hipparchus.geometry.LocalizedGeometryFormats;
31  import org.hipparchus.linear.MatrixUtils;
32  import org.hipparchus.linear.RealMatrix;
33  import org.hipparchus.random.UnitSphereRandomVectorGenerator;
34  import org.hipparchus.random.Well1024a;
35  import org.hipparchus.util.FastMath;
36  import org.hipparchus.util.MathUtils;
37  import org.junit.jupiter.api.Assertions;
38  import org.junit.jupiter.api.Test;
39  
40  import static org.junit.jupiter.api.Assertions.assertEquals;
41  import static org.junit.jupiter.api.Assertions.assertTrue;
42  import static org.junit.jupiter.api.Assertions.fail;
43  
44  
45  class FieldRotationDSTest {
46  
47      @Test
48      void testIdentity() {
49  
50          FieldRotation<DerivativeStructure> r = createRotation(1, 0, 0, 0, false);
51          checkVector(r.applyTo(createVector(1, 0, 0)), createVector(1, 0, 0));
52          checkVector(r.applyTo(createVector(0, 1, 0)), createVector(0, 1, 0));
53          checkVector(r.applyTo(createVector(0, 0, 1)), createVector(0, 0, 1));
54          checkAngle(r.getAngle(), 0);
55  
56          r = createRotation(-1, 0, 0, 0, false);
57          checkVector(r.applyTo(createVector(1, 0, 0)), createVector(1, 0, 0));
58          checkVector(r.applyTo(createVector(0, 1, 0)), createVector(0, 1, 0));
59          checkVector(r.applyTo(createVector(0, 0, 1)), createVector(0, 0, 1));
60          checkAngle(r.getAngle(), 0);
61  
62          r = createRotation(42, 0, 0, 0, true);
63          checkVector(r.applyTo(createVector(1, 0, 0)), createVector(1, 0, 0));
64          checkVector(r.applyTo(createVector(0, 1, 0)), createVector(0, 1, 0));
65          checkVector(r.applyTo(createVector(0, 0, 1)), createVector(0, 0, 1));
66          checkAngle(r.getAngle(), 0);
67  
68      }
69  
70      @Test
71      void testAxisAngleVectorOperator() throws MathIllegalArgumentException {
72  
73          FieldRotation<DerivativeStructure> r = new FieldRotation<>(createAxis(10, 10, 10),
74                                                                     createAngle(2 * FastMath.PI / 3) ,
75                                                                     RotationConvention.VECTOR_OPERATOR);
76          checkVector(r.applyTo(createVector(1, 0, 0)), createVector(0, 1, 0));
77          checkVector(r.applyTo(createVector(0, 1, 0)), createVector(0, 0, 1));
78          checkVector(r.applyTo(createVector(0, 0, 1)), createVector(1, 0, 0));
79          double s = 1 / FastMath.sqrt(3);
80          checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), createVector( s,  s,  s));
81          checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), createVector(-s, -s, -s));
82          checkAngle(r.getAngle(), 2 * FastMath.PI / 3);
83  
84          try {
85              new FieldRotation<>(createAxis(0, 0, 0), createAngle(2 * FastMath.PI / 3), RotationConvention.VECTOR_OPERATOR);
86              fail("an exception should have been thrown");
87          } catch (MathIllegalArgumentException e) {
88              Assertions.assertEquals(LocalizedGeometryFormats.ZERO_NORM_FOR_ROTATION_AXIS, e.getSpecifier());
89          }
90  
91          r = new FieldRotation<>(createAxis(0, 0, 1),
92                                  createAngle(1.5 * FastMath.PI),
93                                  RotationConvention.VECTOR_OPERATOR);
94          checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), createVector(0, 0, -1));
95          checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), createVector(0, 0, +1));
96          checkAngle(r.getAngle(), MathUtils.SEMI_PI);
97  
98          r = new FieldRotation<>(createAxis(0, 1, 0),
99                                  createAngle(FastMath.PI),
100                                 RotationConvention.VECTOR_OPERATOR);
101         checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), createVector(0, +1, 0));
102         checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), createVector(0, -1, 0));
103         checkAngle(r.getAngle(), FastMath.PI);
104 
105         checkVector(createRotation(1, 0, 0, 0, false).getAxis(RotationConvention.VECTOR_OPERATOR), createVector(+1, 0, 0));
106         checkVector(createRotation(1, 0, 0, 0, false).getAxis(RotationConvention.FRAME_TRANSFORM), createVector(-1, 0, 0));
107 
108     }
109 
110     @Test
111     void testAxisAngleFrameTransform() throws MathIllegalArgumentException {
112 
113         FieldRotation<DerivativeStructure> r = new FieldRotation<>(createAxis(10, 10, 10),
114                                                                    createAngle(2 * FastMath.PI / 3) ,
115                                                                    RotationConvention.FRAME_TRANSFORM);
116         checkVector(r.applyTo(createVector(1, 0, 0)), createVector(0, 0, 1));
117         checkVector(r.applyTo(createVector(0, 1, 0)), createVector(1, 0, 0));
118         checkVector(r.applyTo(createVector(0, 0, 1)), createVector(0, 1, 0));
119         double s = 1 / FastMath.sqrt(3);
120         checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), createVector( s,  s,  s));
121         checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), createVector(-s, -s, -s));
122         checkAngle(r.getAngle(), 2 * FastMath.PI / 3);
123 
124         try {
125             new FieldRotation<>(createAxis(0, 0, 0),
126                                 createAngle(2 * FastMath.PI / 3),
127                                 RotationConvention.FRAME_TRANSFORM);
128             fail("an exception should have been thrown");
129         } catch (MathIllegalArgumentException e) {
130             Assertions.assertEquals(LocalizedGeometryFormats.ZERO_NORM_FOR_ROTATION_AXIS, e.getSpecifier());
131         }
132 
133         r = new FieldRotation<>(createAxis(0, 0, 1),
134                                 createAngle(1.5 * FastMath.PI),
135                                 RotationConvention.FRAME_TRANSFORM);
136         checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), createVector(0, 0, -1));
137         checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), createVector(0, 0, +1));
138         checkAngle(r.getAngle(), MathUtils.SEMI_PI);
139 
140         r = new FieldRotation<>(createAxis(0, 1, 0),
141                                 createAngle(FastMath.PI),
142                                 RotationConvention.FRAME_TRANSFORM);
143         checkVector(r.getAxis(RotationConvention.FRAME_TRANSFORM), createVector(0, +1, 0));
144         checkVector(r.getAxis(RotationConvention.VECTOR_OPERATOR), createVector(0, -1, 0));
145         checkAngle(r.getAngle(), FastMath.PI);
146 
147         checkVector(createRotation(1, 0, 0, 0, false).getAxis(RotationConvention.FRAME_TRANSFORM), createVector(-1, 0, 0));
148         checkVector(createRotation(1, 0, 0, 0, false).getAxis(RotationConvention.VECTOR_OPERATOR), createVector(+1, 0, 0));
149 
150     }
151 
152     @Test
153     void testRevert() {
154         double a = 0.001;
155         double b = 0.36;
156         double c = 0.48;
157         double d = 0.8;
158         FieldRotation<DerivativeStructure> r = createRotation(a, b, c, d, true);
159         double a2 = a * a;
160         double b2 = b * b;
161         double c2 = c * c;
162         double d2 = d * d;
163         double den = (a2 + b2 + c2 + d2) * FastMath.sqrt(a2 + b2 + c2 + d2);
164         assertEquals((b2 + c2 + d2) / den, r.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
165         assertEquals(-a * b / den, r.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
166         assertEquals(-a * c / den, r.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
167         assertEquals(-a * d / den, r.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
168         assertEquals(-b * a / den, r.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
169         assertEquals((a2 + c2 + d2) / den, r.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
170         assertEquals(-b * c / den, r.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
171         assertEquals(-b * d / den, r.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
172         assertEquals(-c * a / den, r.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
173         assertEquals(-c * b / den, r.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
174         assertEquals((a2 + b2 + d2) / den, r.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
175         assertEquals(-c * d / den, r.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
176         assertEquals(-d * a / den, r.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
177         assertEquals(-d * b / den, r.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
178         assertEquals(-d * c / den, r.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
179         assertEquals((a2 + b2 + c2) / den, r.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
180         FieldRotation<DerivativeStructure> reverted = r.revert();
181         FieldRotation<DerivativeStructure> rrT = r.applyTo(reverted);
182         checkRotationDS(rrT, 1, 0, 0, 0);
183         assertEquals(0, rrT.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
184         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
185         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
186         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
187         assertEquals(0, rrT.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
188         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
189         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
190         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
191         assertEquals(0, rrT.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
192         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
193         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
194         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
195         assertEquals(0, rrT.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
196         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
197         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
198         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
199         FieldRotation<DerivativeStructure> rTr = reverted.applyTo(r);
200         checkRotationDS(rTr, 1, 0, 0, 0);
201         assertEquals(0, rTr.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
202         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
203         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
204         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
205         assertEquals(0, rTr.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
206         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
207         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
208         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
209         assertEquals(0, rTr.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
210         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
211         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
212         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
213         assertEquals(0, rTr.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
214         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
215         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
216         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
217         assertEquals(r.getAngle().getReal(), reverted.getAngle().getReal(), 1.0e-15);
218         assertEquals(-1,
219                             FieldVector3D.dotProduct(r.getAxis(RotationConvention.VECTOR_OPERATOR),
220                                                      reverted.getAxis(RotationConvention.VECTOR_OPERATOR)).getReal(),
221                             1.0e-15);
222     }
223 
224     @Test
225     void testRevertVectorOperator() {
226         double a = 0.001;
227         double b = 0.36;
228         double c = 0.48;
229         double d = 0.8;
230         FieldRotation<DerivativeStructure> r = createRotation(a, b, c, d, true);
231         double a2 = a * a;
232         double b2 = b * b;
233         double c2 = c * c;
234         double d2 = d * d;
235         double den = (a2 + b2 + c2 + d2) * FastMath.sqrt(a2 + b2 + c2 + d2);
236         assertEquals((b2 + c2 + d2) / den, r.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
237         assertEquals(-a * b / den, r.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
238         assertEquals(-a * c / den, r.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
239         assertEquals(-a * d / den, r.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
240         assertEquals(-b * a / den, r.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
241         assertEquals((a2 + c2 + d2) / den, r.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
242         assertEquals(-b * c / den, r.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
243         assertEquals(-b * d / den, r.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
244         assertEquals(-c * a / den, r.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
245         assertEquals(-c * b / den, r.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
246         assertEquals((a2 + b2 + d2) / den, r.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
247         assertEquals(-c * d / den, r.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
248         assertEquals(-d * a / den, r.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
249         assertEquals(-d * b / den, r.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
250         assertEquals(-d * c / den, r.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
251         assertEquals((a2 + b2 + c2) / den, r.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
252         FieldRotation<DerivativeStructure> reverted = r.revert();
253         FieldRotation<DerivativeStructure> rrT = r.compose(reverted, RotationConvention.VECTOR_OPERATOR);
254         checkRotationDS(rrT, 1, 0, 0, 0);
255         assertEquals(0, rrT.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
256         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
257         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
258         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
259         assertEquals(0, rrT.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
260         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
261         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
262         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
263         assertEquals(0, rrT.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
264         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
265         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
266         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
267         assertEquals(0, rrT.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
268         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
269         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
270         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
271         FieldRotation<DerivativeStructure> rTr = reverted.compose(r, RotationConvention.VECTOR_OPERATOR);
272         checkRotationDS(rTr, 1, 0, 0, 0);
273         assertEquals(0, rTr.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
274         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
275         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
276         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
277         assertEquals(0, rTr.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
278         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
279         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
280         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
281         assertEquals(0, rTr.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
282         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
283         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
284         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
285         assertEquals(0, rTr.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
286         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
287         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
288         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
289         assertEquals(r.getAngle().getReal(), reverted.getAngle().getReal(), 1.0e-15);
290         assertEquals(-1,
291                             FieldVector3D.dotProduct(r.getAxis(RotationConvention.VECTOR_OPERATOR),
292                                                      reverted.getAxis(RotationConvention.VECTOR_OPERATOR)).getReal(),
293                             1.0e-15);
294     }
295 
296     @Test
297     void testRevertFrameTransform() {
298         double a = 0.001;
299         double b = 0.36;
300         double c = 0.48;
301         double d = 0.8;
302         FieldRotation<DerivativeStructure> r = createRotation(a, b, c, d, true);
303         double a2 = a * a;
304         double b2 = b * b;
305         double c2 = c * c;
306         double d2 = d * d;
307         double den = (a2 + b2 + c2 + d2) * FastMath.sqrt(a2 + b2 + c2 + d2);
308         assertEquals((b2 + c2 + d2) / den, r.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
309         assertEquals(-a * b / den, r.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
310         assertEquals(-a * c / den, r.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
311         assertEquals(-a * d / den, r.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
312         assertEquals(-b * a / den, r.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
313         assertEquals((a2 + c2 + d2) / den, r.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
314         assertEquals(-b * c / den, r.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
315         assertEquals(-b * d / den, r.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
316         assertEquals(-c * a / den, r.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
317         assertEquals(-c * b / den, r.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
318         assertEquals((a2 + b2 + d2) / den, r.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
319         assertEquals(-c * d / den, r.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
320         assertEquals(-d * a / den, r.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
321         assertEquals(-d * b / den, r.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
322         assertEquals(-d * c / den, r.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
323         assertEquals((a2 + b2 + c2) / den, r.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
324         FieldRotation<DerivativeStructure> reverted = r.revert();
325         FieldRotation<DerivativeStructure> rrT = r.compose(reverted, RotationConvention.FRAME_TRANSFORM);
326         checkRotationDS(rrT, 1, 0, 0, 0);
327         assertEquals(0, rrT.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
328         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
329         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
330         assertEquals(0, rrT.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
331         assertEquals(0, rrT.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
332         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
333         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
334         assertEquals(0, rrT.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
335         assertEquals(0, rrT.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
336         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
337         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
338         assertEquals(0, rrT.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
339         assertEquals(0, rrT.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
340         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
341         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
342         assertEquals(0, rrT.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
343         FieldRotation<DerivativeStructure> rTr = reverted.compose(r, RotationConvention.FRAME_TRANSFORM);
344         checkRotationDS(rTr, 1, 0, 0, 0);
345         assertEquals(0, rTr.getQ0().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
346         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
347         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
348         assertEquals(0, rTr.getQ0().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
349         assertEquals(0, rTr.getQ1().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
350         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
351         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
352         assertEquals(0, rTr.getQ1().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
353         assertEquals(0, rTr.getQ2().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
354         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
355         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
356         assertEquals(0, rTr.getQ2().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
357         assertEquals(0, rTr.getQ3().getPartialDerivative(1, 0, 0, 0), 1.0e-15);
358         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 1, 0, 0), 1.0e-15);
359         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 0, 1, 0), 1.0e-15);
360         assertEquals(0, rTr.getQ3().getPartialDerivative(0, 0, 0, 1), 1.0e-15);
361         assertEquals(r.getAngle().getReal(), reverted.getAngle().getReal(), 1.0e-15);
362         assertEquals(-1,
363                             FieldVector3D.dotProduct(r.getAxis(RotationConvention.FRAME_TRANSFORM),
364                                                      reverted.getAxis(RotationConvention.FRAME_TRANSFORM)).getReal(),
365                             1.0e-15);
366     }
367 
368     @Test
369     void testVectorOnePair() throws MathRuntimeException {
370 
371         FieldVector3D<DerivativeStructure> u = createVector(3, 2, 1);
372         FieldVector3D<DerivativeStructure> v = createVector(-4, 2, 2);
373         FieldRotation<DerivativeStructure> r = new FieldRotation<>(u, v);
374         checkVector(r.applyTo(u.scalarMultiply(v.getNorm())), v.scalarMultiply(u.getNorm()));
375 
376         checkAngle(new FieldRotation<>(u, u.negate()).getAngle(), FastMath.PI);
377 
378         try {
379             new FieldRotation<>(u, createVector(0, 0, 0));
380             fail("an exception should have been thrown");
381         } catch (MathRuntimeException e) {
382             // expected behavior
383         }
384 
385     }
386 
387     @Test
388     void testVectorTwoPairs() throws MathRuntimeException {
389 
390         FieldVector3D<DerivativeStructure> u1 = createVector(3, 0, 0);
391         FieldVector3D<DerivativeStructure> u2 = createVector(0, 5, 0);
392         FieldVector3D<DerivativeStructure> v1 = createVector(0, 0, 2);
393         FieldVector3D<DerivativeStructure> v2 = createVector(-2, 0, 2);
394         FieldRotation<DerivativeStructure> r = new FieldRotation<>(u1, u2, v1, v2);
395         checkVector(r.applyTo(createVector(1, 0, 0)), createVector(0, 0, 1));
396         checkVector(r.applyTo(createVector(0, 1, 0)), createVector(-1, 0, 0));
397 
398         r = new FieldRotation<>(u1, u2, u1.negate(), u2.negate());
399         FieldVector3D<DerivativeStructure> axis = r.getAxis(RotationConvention.VECTOR_OPERATOR);
400         if (FieldVector3D.dotProduct(axis, createVector(0, 0, 1)).getReal() > 0) {
401             checkVector(axis, createVector(0, 0, 1));
402         } else {
403             checkVector(axis, createVector(0, 0, -1));
404         }
405         checkAngle(r.getAngle(), FastMath.PI);
406 
407         double sqrt = FastMath.sqrt(2) / 2;
408         r = new FieldRotation<>(createVector(1, 0, 0),  createVector(0, 1, 0),
409                            createVector(0.5, 0.5,  sqrt),
410                            createVector(0.5, 0.5, -sqrt));
411         checkRotationDS(r, sqrt, 0.5, 0.5, 0);
412 
413         r = new FieldRotation<>(u1, u2, u1, FieldVector3D.crossProduct(u1, u2));
414         checkRotationDS(r, sqrt, -sqrt, 0, 0);
415 
416         checkRotationDS(new FieldRotation<>(u1, u2, u1, u2), 1, 0, 0, 0);
417 
418         try {
419             new FieldRotation<>(u1, u2, createVector(0, 0, 0), v2);
420             fail("an exception should have been thrown");
421         } catch (MathRuntimeException e) {
422             // expected behavior
423         }
424 
425     }
426 
427     @Test
428     void testMatrix()
429         throws MathIllegalArgumentException {
430 
431         try {
432             createRotation(new double[][] {
433                 { 0.0, 1.0, 0.0 },
434                 { 1.0, 0.0, 0.0 }
435             }, 1.0e-7);
436             fail("Expecting MathIllegalArgumentException");
437         } catch (MathIllegalArgumentException nrme) {
438             // expected behavior
439         }
440 
441         try {
442             createRotation(new double[][] {
443                 {  0.445888,  0.797184, -0.407040 },
444                 {  0.821760, -0.184320,  0.539200 },
445                 { -0.354816,  0.574912,  0.737280 }
446             }, 1.0e-7);
447             fail("Expecting MathIllegalArgumentException");
448         } catch (MathIllegalArgumentException nrme) {
449             // expected behavior
450         }
451 
452         try {
453             createRotation(new double[][] {
454                 {  0.4,  0.8, -0.4 },
455                 { -0.4,  0.6,  0.7 },
456                 {  0.8, -0.2,  0.5 }
457             }, 1.0e-15);
458             fail("Expecting MathIllegalArgumentException");
459         } catch (MathIllegalArgumentException nrme) {
460             // expected behavior
461         }
462 
463         checkRotationDS(createRotation(new double[][] {
464             {  0.445888,  0.797184, -0.407040 },
465             { -0.354816,  0.574912,  0.737280 },
466             {  0.821760, -0.184320,  0.539200 }
467         }, 1.0e-10),
468         0.8, 0.288, 0.384, 0.36);
469 
470         checkRotationDS(createRotation(new double[][] {
471             {  0.539200,  0.737280,  0.407040 },
472             {  0.184320, -0.574912,  0.797184 },
473             {  0.821760, -0.354816, -0.445888 }
474         }, 1.0e-10),
475         0.36, 0.8, 0.288, 0.384);
476 
477         checkRotationDS(createRotation(new double[][] {
478             { -0.445888,  0.797184, -0.407040 },
479             {  0.354816,  0.574912,  0.737280 },
480             {  0.821760,  0.184320, -0.539200 }
481         }, 1.0e-10),
482         0.384, 0.36, 0.8, 0.288);
483 
484         checkRotationDS(createRotation(new double[][] {
485             { -0.539200,  0.737280,  0.407040 },
486             { -0.184320, -0.574912,  0.797184 },
487             {  0.821760,  0.354816,  0.445888 }
488         }, 1.0e-10),
489         0.288, 0.384, 0.36, 0.8);
490 
491         double[][] m1 = { { 0.0, 1.0, 0.0 },
492             { 0.0, 0.0, 1.0 },
493             { 1.0, 0.0, 0.0 } };
494         FieldRotation<DerivativeStructure> r = createRotation(m1, 1.0e-7);
495         checkVector(r.applyTo(createVector(1, 0, 0)), createVector(0, 0, 1));
496         checkVector(r.applyTo(createVector(0, 1, 0)), createVector(1, 0, 0));
497         checkVector(r.applyTo(createVector(0, 0, 1)), createVector(0, 1, 0));
498 
499         double[][] m2 = { { 0.83203, -0.55012, -0.07139 },
500             { 0.48293,  0.78164, -0.39474 },
501             { 0.27296,  0.29396,  0.91602 } };
502         r = createRotation(m2, 1.0e-12);
503 
504         DerivativeStructure[][] m3 = r.getMatrix();
505         double d00 = m2[0][0] - m3[0][0].getReal();
506         double d01 = m2[0][1] - m3[0][1].getReal();
507         double d02 = m2[0][2] - m3[0][2].getReal();
508         double d10 = m2[1][0] - m3[1][0].getReal();
509         double d11 = m2[1][1] - m3[1][1].getReal();
510         double d12 = m2[1][2] - m3[1][2].getReal();
511         double d20 = m2[2][0] - m3[2][0].getReal();
512         double d21 = m2[2][1] - m3[2][1].getReal();
513         double d22 = m2[2][2] - m3[2][2].getReal();
514 
515         assertTrue(FastMath.abs(d00) < 6.0e-6);
516         assertTrue(FastMath.abs(d01) < 6.0e-6);
517         assertTrue(FastMath.abs(d02) < 6.0e-6);
518         assertTrue(FastMath.abs(d10) < 6.0e-6);
519         assertTrue(FastMath.abs(d11) < 6.0e-6);
520         assertTrue(FastMath.abs(d12) < 6.0e-6);
521         assertTrue(FastMath.abs(d20) < 6.0e-6);
522         assertTrue(FastMath.abs(d21) < 6.0e-6);
523         assertTrue(FastMath.abs(d22) < 6.0e-6);
524 
525         assertTrue(FastMath.abs(d00) > 4.0e-7);
526         assertTrue(FastMath.abs(d01) > 4.0e-7);
527         assertTrue(FastMath.abs(d02) > 4.0e-7);
528         assertTrue(FastMath.abs(d10) > 4.0e-7);
529         assertTrue(FastMath.abs(d11) > 4.0e-7);
530         assertTrue(FastMath.abs(d12) > 4.0e-7);
531         assertTrue(FastMath.abs(d20) > 4.0e-7);
532         assertTrue(FastMath.abs(d21) > 4.0e-7);
533         assertTrue(FastMath.abs(d22) > 4.0e-7);
534 
535         for (int i = 0; i < 3; ++i) {
536             for (int j = 0; j < 3; ++j) {
537                 double m3tm3 = m3[i][0].getReal() * m3[j][0].getReal() +
538                                m3[i][1].getReal() * m3[j][1].getReal() +
539                                m3[i][2].getReal() * m3[j][2].getReal();
540                 if (i == j) {
541                     assertTrue(FastMath.abs(m3tm3 - 1.0) < 1.0e-10);
542                 } else {
543                     assertTrue(FastMath.abs(m3tm3) < 1.0e-10);
544                 }
545             }
546         }
547 
548         checkVector(r.applyTo(createVector(1, 0, 0)), new FieldVector3D<>(m3[0][0], m3[1][0], m3[2][0]));
549         checkVector(r.applyTo(createVector(0, 1, 0)), new FieldVector3D<>(m3[0][1], m3[1][1], m3[2][1]));
550         checkVector(r.applyTo(createVector(0, 0, 1)), new FieldVector3D<>(m3[0][2], m3[1][2], m3[2][2]));
551 
552         double[][] m4 = { { 1.0,  0.0,  0.0 },
553             { 0.0, -1.0,  0.0 },
554             { 0.0,  0.0, -1.0 } };
555         r = createRotation(m4, 1.0e-7);
556         checkAngle(r.getAngle(), FastMath.PI);
557 
558         try {
559             double[][] m5 = { { 0.0, 0.0, 1.0 },
560                 { 0.0, 1.0, 0.0 },
561                 { 1.0, 0.0, 0.0 } };
562             r = createRotation(m5, 1.0e-7);
563             fail("got " + r + ", should have caught an exception");
564         } catch (MathIllegalArgumentException e) {
565             // expected
566         }
567 
568     }
569 
570     @Test
571     void testAngles()
572         throws MathIllegalStateException {
573 
574         DSFactory factory = new DSFactory(3, 1);
575         for (RotationConvention convention : RotationConvention.values()) {
576             RotationOrder[] CardanOrders = {
577                 RotationOrder.XYZ, RotationOrder.XZY, RotationOrder.YXZ,
578                 RotationOrder.YZX, RotationOrder.ZXY, RotationOrder.ZYX
579             };
580 
581             for (final RotationOrder cardanOrder : CardanOrders) {
582                 for (double alpha1 = 0.1; alpha1 < 6.2; alpha1 += 0.3) {
583                     for (double alpha2 = -1.55; alpha2 < 1.55; alpha2 += 0.3) {
584                         for (double alpha3 = 0.1; alpha3 < 6.2; alpha3 += 0.3) {
585                             FieldRotation<DerivativeStructure> r =
586                                     new FieldRotation<>(cardanOrder,
587                                                         convention,
588                                                         factory.variable(0, alpha1),
589                                                         factory.variable(1, alpha2),
590                                                         factory.variable(2, alpha3));
591                             DerivativeStructure[] angles = r.getAngles(cardanOrder, convention);
592                             checkAngle(angles[0], alpha1);
593                             checkAngle(angles[1], alpha2);
594                             checkAngle(angles[2], alpha3);
595                         }
596                     }
597                 }
598             }
599 
600             RotationOrder[] EulerOrders = {
601                 RotationOrder.XYX, RotationOrder.XZX, RotationOrder.YXY,
602                 RotationOrder.YZY, RotationOrder.ZXZ, RotationOrder.ZYZ
603             };
604 
605             for (final RotationOrder eulerOrder : EulerOrders) {
606                 for (double alpha1 = 0.1; alpha1 < 6.2; alpha1 += 0.3) {
607                     for (double alpha2 = 0.05; alpha2 < 3.1; alpha2 += 0.3) {
608                         for (double alpha3 = 0.1; alpha3 < 6.2; alpha3 += 0.3) {
609                             FieldRotation<DerivativeStructure> r =
610                                     new FieldRotation<>(eulerOrder,
611                                                         convention,
612                                                         factory.variable(0, alpha1),
613                                                         factory.variable(1, alpha2),
614                                                         factory.variable(2, alpha3));
615                             DerivativeStructure[] angles = r.getAngles(eulerOrder, convention);
616                             checkAngle(angles[0], alpha1);
617                             checkAngle(angles[1], alpha2);
618                             checkAngle(angles[2], alpha3);
619                         }
620                     }
621                 }
622             }
623         }
624 
625     }
626 
627     @Test
628     void testSingularities() {
629 
630         DSFactory factory = new DSFactory(3, 1);
631         for (RotationConvention convention : RotationConvention.values()) {
632             RotationOrder[] CardanOrders = {
633                 RotationOrder.XYZ, RotationOrder.XZY, RotationOrder.YXZ,
634                 RotationOrder.YZX, RotationOrder.ZXY, RotationOrder.ZYX
635             };
636 
637             double[] singularCardanAngle = {
638                 -FastMath.PI / 2, -FastMath.PI / 2 + 1.0e-12, -FastMath.PI / 2 + 1.0e-10,
639                 FastMath.PI / 2 - 1.0e-10, FastMath.PI / 2 - 1.0e-12, FastMath.PI / 2
640             };
641             for (final RotationOrder cardanOrder : CardanOrders) {
642                 for (final double v : singularCardanAngle) {
643                     FieldRotation<DerivativeStructure> r = new FieldRotation<>(cardanOrder,
644                                                                                convention,
645                                                                                factory.variable(0, 0.1),
646                                                                                factory.variable(1, v),
647                                                                                factory.variable(2, 0.3));
648                     assertEquals(v, r.getAngles(cardanOrder, convention)[1].getReal(), 4.5e-16);
649                 }
650             }
651 
652             RotationOrder[] EulerOrders = {
653                 RotationOrder.XYX, RotationOrder.XZX, RotationOrder.YXY,
654                 RotationOrder.YZY, RotationOrder.ZXZ, RotationOrder.ZYZ
655             };
656 
657             double[] singularEulerAngle = { 0, 1.0e-12, 1.0e-10, FastMath.PI - 1.0e-10, FastMath.PI - 1.0e-12, FastMath.PI };
658             for (final RotationOrder eulerOrder : EulerOrders) {
659                 for (final double v : singularEulerAngle) {
660                     FieldRotation<DerivativeStructure> r = new FieldRotation<>(eulerOrder,
661                                                                                convention,
662                                                                                factory.variable(0, 0.1),
663                                                                                factory.variable(1, v),
664                                                                                factory.variable(2, 0.3));
665                     r.getAngles(eulerOrder, convention);
666                     assertEquals(v, r.getAngles(eulerOrder, convention)[1].getReal(), 1.0e-24);
667                 }
668             }
669 
670         }
671     }
672 
673     @Test
674     void testQuaternion() throws MathIllegalArgumentException {
675 
676         FieldRotation<DerivativeStructure> r1 = new FieldRotation<>(createVector(2, -3, 5),
677                                                                     createAngle(1.7),
678                                                                     RotationConvention.VECTOR_OPERATOR);
679         double n = 23.5;
680         FieldRotation<DerivativeStructure> r2 = new FieldRotation<>(r1.getQ0().multiply(n), r1.getQ1().multiply(n),
681                                                                     r1.getQ2().multiply(n), r1.getQ3().multiply(n),
682                                                                     true);
683         for (double x = -0.9; x < 0.9; x += 0.2) {
684             for (double y = -0.9; y < 0.9; y += 0.2) {
685                 for (double z = -0.9; z < 0.9; z += 0.2) {
686                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
687                     checkVector(r2.applyTo(u), r1.applyTo(u));
688                 }
689             }
690         }
691 
692         r1 = createRotation(0.288,  0.384,  0.36,  0.8, false);
693         checkRotationDS(r1,
694                         -r1.getQ0().getReal(), -r1.getQ1().getReal(),
695                         -r1.getQ2().getReal(), -r1.getQ3().getReal());
696         assertEquals(0.288, r1.toRotation().getQ0(), 1.0e-15);
697         assertEquals(0.384, r1.toRotation().getQ1(), 1.0e-15);
698         assertEquals(0.36,  r1.toRotation().getQ2(), 1.0e-15);
699         assertEquals(0.8,   r1.toRotation().getQ3(), 1.0e-15);
700 
701     }
702 
703     @Test
704     void testApplyToRotation() throws MathIllegalArgumentException {
705 
706         FieldRotation<DerivativeStructure> r1       = new FieldRotation<>(createVector(2, -3, 5),
707                                                                           createAngle(1.7),
708                                                                           RotationConvention.VECTOR_OPERATOR);
709         FieldRotation<DerivativeStructure> r2       = new FieldRotation<>(createVector(-1, 3, 2),
710                                                                           createAngle(0.3),
711                                                                           RotationConvention.VECTOR_OPERATOR);
712         FieldRotation<DerivativeStructure> r3       = r2.applyTo(r1);
713         FieldRotation<DerivativeStructure> r3Double = r2.applyTo(new Rotation(r1.getQ0().getReal(),
714                                                                               r1.getQ1().getReal(),
715                                                                               r1.getQ2().getReal(),
716                                                                               r1.getQ3().getReal(),
717                                                                               false));
718 
719         for (double x = -0.9; x < 0.9; x += 0.2) {
720             for (double y = -0.9; y < 0.9; y += 0.2) {
721                 for (double z = -0.9; z < 0.9; z += 0.2) {
722                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
723                     checkVector(r2.applyTo(r1.applyTo(u)), r3.applyTo(u));
724                     checkVector(r2.applyTo(r1.applyTo(u)), r3Double.applyTo(u));
725                 }
726             }
727         }
728 
729     }
730 
731     @Test
732     void testComposeVectorOperator() throws MathIllegalArgumentException {
733 
734         FieldRotation<DerivativeStructure> r1       = new FieldRotation<>(createVector(2, -3, 5),
735                                                                           createAngle(1.7),
736                                                                           RotationConvention.VECTOR_OPERATOR);
737         FieldRotation<DerivativeStructure> r2       = new FieldRotation<>(createVector(-1, 3, 2),
738                                                                           createAngle(0.3),
739                                                                           RotationConvention.VECTOR_OPERATOR);
740         FieldRotation<DerivativeStructure> r3       = r2.compose(r1, RotationConvention.VECTOR_OPERATOR);
741         FieldRotation<DerivativeStructure> r3Double = r2.compose(new Rotation(r1.getQ0().getReal(),
742                                                                               r1.getQ1().getReal(),
743                                                                               r1.getQ2().getReal(),
744                                                                               r1.getQ3().getReal(),
745                                                                               false),
746                                                                  RotationConvention.VECTOR_OPERATOR);
747 
748         for (double x = -0.9; x < 0.9; x += 0.2) {
749             for (double y = -0.9; y < 0.9; y += 0.2) {
750                 for (double z = -0.9; z < 0.9; z += 0.2) {
751                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
752                     checkVector(r2.applyTo(r1.applyTo(u)), r3.applyTo(u));
753                     checkVector(r2.applyTo(r1.applyTo(u)), r3Double.applyTo(u));
754                 }
755             }
756         }
757 
758     }
759 
760     @Test
761     void testComposeFrameTransform() throws MathIllegalArgumentException {
762 
763         FieldRotation<DerivativeStructure> r1       = new FieldRotation<>(createVector(2, -3, 5),
764                                                                           createAngle(1.7),
765                                                                           RotationConvention.FRAME_TRANSFORM);
766         FieldRotation<DerivativeStructure> r2       = new FieldRotation<>(createVector(-1, 3, 2),
767                                                                           createAngle(0.3),
768                                                                           RotationConvention.FRAME_TRANSFORM);
769         FieldRotation<DerivativeStructure> r3       = r2.compose(r1, RotationConvention.FRAME_TRANSFORM);
770         FieldRotation<DerivativeStructure> r3Double = r2.compose(new Rotation(r1.getQ0().getReal(),
771                                                                               r1.getQ1().getReal(),
772                                                                               r1.getQ2().getReal(),
773                                                                               r1.getQ3().getReal(),
774                                                                               false),
775                                                                  RotationConvention.FRAME_TRANSFORM);
776 
777         for (double x = -0.9; x < 0.9; x += 0.2) {
778             for (double y = -0.9; y < 0.9; y += 0.2) {
779                 for (double z = -0.9; z < 0.9; z += 0.2) {
780                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
781                     checkVector(r1.applyTo(r2.applyTo(u)), r3.applyTo(u));
782                     checkVector(r1.applyTo(r2.applyTo(u)), r3Double.applyTo(u));
783                 }
784             }
785         }
786 
787     }
788 
789     @Test
790     void testApplyInverseToRotation() throws MathIllegalArgumentException {
791 
792         FieldRotation<DerivativeStructure> r1 = new FieldRotation<>(createVector(2, -3, 5),
793                                                                     createAngle(1.7),
794                                                                     RotationConvention.VECTOR_OPERATOR);
795         FieldRotation<DerivativeStructure> r2 = new FieldRotation<>(createVector(-1, 3, 2),
796                                                                     createAngle(0.3),
797                                                                     RotationConvention.VECTOR_OPERATOR);
798         FieldRotation<DerivativeStructure> r3 = r2.applyInverseTo(r1);
799         FieldRotation<DerivativeStructure> r3Double = r2.applyInverseTo(new Rotation(r1.getQ0().getReal(),
800                                                                                      r1.getQ1().getReal(),
801                                                                                      r1.getQ2().getReal(),
802                                                                                      r1.getQ3().getReal(),
803                                                                                     false));
804 
805         for (double x = -0.9; x < 0.9; x += 0.2) {
806             for (double y = -0.9; y < 0.9; y += 0.2) {
807                 for (double z = -0.9; z < 0.9; z += 0.2) {
808                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
809                     checkVector(r2.applyInverseTo(r1.applyTo(u)), r3.applyTo(u));
810                     checkVector(r2.applyInverseTo(r1.applyTo(u)), r3Double.applyTo(u));
811                 }
812             }
813         }
814 
815     }
816 
817     @Test
818     void testComposeInverseVectorOperator() throws MathIllegalArgumentException {
819 
820         FieldRotation<DerivativeStructure> r1 = new FieldRotation<>(createVector(2, -3, 5),
821                                                                     createAngle(1.7),
822                                                                     RotationConvention.VECTOR_OPERATOR);
823         FieldRotation<DerivativeStructure> r2 = new FieldRotation<>(createVector(-1, 3, 2),
824                                                                     createAngle(0.3),
825                                                                     RotationConvention.VECTOR_OPERATOR);
826         FieldRotation<DerivativeStructure> r3 = r2.composeInverse(r1, RotationConvention.VECTOR_OPERATOR);
827         FieldRotation<DerivativeStructure> r3Double = r2.composeInverse(new Rotation(r1.getQ0().getReal(),
828                                                                                      r1.getQ1().getReal(),
829                                                                                      r1.getQ2().getReal(),
830                                                                                      r1.getQ3().getReal(),
831                                                                                      false),
832                                                                         RotationConvention.VECTOR_OPERATOR);
833 
834         for (double x = -0.9; x < 0.9; x += 0.2) {
835             for (double y = -0.9; y < 0.9; y += 0.2) {
836                 for (double z = -0.9; z < 0.9; z += 0.2) {
837                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
838                     checkVector(r2.applyInverseTo(r1.applyTo(u)), r3.applyTo(u));
839                     checkVector(r2.applyInverseTo(r1.applyTo(u)), r3Double.applyTo(u));
840                 }
841             }
842         }
843 
844     }
845 
846     @Test
847     void testComposeInverseframeTransform() throws MathIllegalArgumentException {
848 
849         FieldRotation<DerivativeStructure> r1 = new FieldRotation<>(createVector(2, -3, 5),
850                                                                     createAngle(1.7),
851                                                                     RotationConvention.FRAME_TRANSFORM);
852         FieldRotation<DerivativeStructure> r2 = new FieldRotation<>(createVector(-1, 3, 2),
853                                                                     createAngle(0.3),
854                                                                     RotationConvention.FRAME_TRANSFORM);
855         FieldRotation<DerivativeStructure> r3 = r2.composeInverse(r1, RotationConvention.FRAME_TRANSFORM);
856         FieldRotation<DerivativeStructure> r3Double = r2.composeInverse(new Rotation(r1.getQ0().getReal(),
857                                                                                      r1.getQ1().getReal(),
858                                                                                      r1.getQ2().getReal(),
859                                                                                      r1.getQ3().getReal(),
860                                                                                      false),
861                                                                         RotationConvention.FRAME_TRANSFORM);
862 
863         for (double x = -0.9; x < 0.9; x += 0.2) {
864             for (double y = -0.9; y < 0.9; y += 0.2) {
865                 for (double z = -0.9; z < 0.9; z += 0.2) {
866                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
867                     checkVector(r1.applyTo(r2.applyInverseTo(u)), r3.applyTo(u));
868                     checkVector(r1.applyTo(r2.applyInverseTo(u)), r3Double.applyTo(u));
869                 }
870             }
871         }
872 
873     }
874 
875     @Test
876     void testDoubleVectors() throws MathIllegalArgumentException {
877 
878         Well1024a random = new Well1024a(0x180b41cfeeffaf67L);
879         UnitSphereRandomVectorGenerator g = new UnitSphereRandomVectorGenerator(3, random);
880         for (int i = 0; i < 10; ++i) {
881             double[] unit = g.nextVector();
882             FieldRotation<DerivativeStructure> r = new FieldRotation<>(createVector(unit[0], unit[1], unit[2]),
883                                                                        createAngle(random.nextDouble()),
884                                                                        RotationConvention.VECTOR_OPERATOR);
885 
886             for (double x = -0.9; x < 0.9; x += 0.2) {
887                 for (double y = -0.9; y < 0.9; y += 0.2) {
888                     for (double z = -0.9; z < 0.9; z += 0.2) {
889                         FieldVector3D<DerivativeStructure> uds   = createVector(x, y, z);
890                         FieldVector3D<DerivativeStructure> ruds  = r.applyTo(uds);
891                         FieldVector3D<DerivativeStructure> rIuds = r.applyInverseTo(uds);
892                         Vector3D   u     = new Vector3D(x, y, z);
893                         FieldVector3D<DerivativeStructure> ru    = r.applyTo(u);
894                         FieldVector3D<DerivativeStructure> rIu   = r.applyInverseTo(u);
895                         DerivativeStructure[] ruArray = new DerivativeStructure[3];
896                         r.applyTo(new double[] { x, y, z}, ruArray);
897                         DerivativeStructure[] rIuArray = new DerivativeStructure[3];
898                         r.applyInverseTo(new double[] { x, y, z}, rIuArray);
899                         checkVector(ruds, ru);
900                         checkVector(ruds, new FieldVector3D<>(ruArray));
901                         checkVector(rIuds, rIu);
902                         checkVector(rIuds, new FieldVector3D<>(rIuArray));
903                     }
904                 }
905             }
906         }
907 
908     }
909 
910     @Test
911     void testDoubleRotations() throws MathIllegalArgumentException {
912 
913         Well1024a random = new Well1024a(0x180b41cfeeffaf67L);
914         UnitSphereRandomVectorGenerator g = new UnitSphereRandomVectorGenerator(3, random);
915         DSFactory factory = new DSFactory(4, 1);
916         for (int i = 0; i < 10; ++i) {
917             double[] unit1 = g.nextVector();
918             Rotation r1 = new Rotation(new Vector3D(unit1[0], unit1[1], unit1[2]),
919                                       random.nextDouble(), RotationConvention.VECTOR_OPERATOR);
920             FieldRotation<DerivativeStructure> r1Prime = new FieldRotation<>(factory.variable(0, r1.getQ0()),
921                                                                              factory.variable(1, r1.getQ1()),
922                                                                              factory.variable(2, r1.getQ2()),
923                                                                              factory.variable(3, r1.getQ3()),
924                                                                              false);
925             double[] unit2 = g.nextVector();
926             FieldRotation<DerivativeStructure> r2 = new FieldRotation<>(createVector(unit2[0], unit2[1], unit2[2]),
927                                                                         createAngle(random.nextDouble()),
928                                                                         RotationConvention.VECTOR_OPERATOR);
929 
930             FieldRotation<DerivativeStructure> rA = FieldRotation.applyTo(r1, r2);
931             FieldRotation<DerivativeStructure> rB = r1Prime.compose(r2, RotationConvention.VECTOR_OPERATOR);
932             FieldRotation<DerivativeStructure> rC = FieldRotation.applyInverseTo(r1, r2);
933             FieldRotation<DerivativeStructure> rD = r1Prime.composeInverse(r2, RotationConvention.VECTOR_OPERATOR);
934 
935             for (double x = -0.9; x < 0.9; x += 0.2) {
936                 for (double y = -0.9; y < 0.9; y += 0.2) {
937                     for (double z = -0.9; z < 0.9; z += 0.2) {
938 
939                         FieldVector3D<DerivativeStructure> uds   = createVector(x, y, z);
940                         checkVector(r1Prime.applyTo(uds), FieldRotation.applyTo(r1, uds));
941                         checkVector(r1Prime.applyInverseTo(uds), FieldRotation.applyInverseTo(r1, uds));
942                         checkVector(rA.applyTo(uds), rB.applyTo(uds));
943                         checkVector(rA.applyInverseTo(uds), rB.applyInverseTo(uds));
944                         checkVector(rC.applyTo(uds), rD.applyTo(uds));
945                         checkVector(rC.applyInverseTo(uds), rD.applyInverseTo(uds));
946 
947                     }
948                 }
949             }
950         }
951 
952     }
953 
954     @Test
955     void testDerivatives() {
956 
957         double eps      = 7.e-16;
958         double kx       = 2;
959         double ky       = -3;
960         double kz       = 5;
961         double n2       = kx * kx + ky * ky + kz * kz;
962         double n        = FastMath.sqrt(n2);
963         double theta    = 1.7;
964         double cosTheta = FastMath.cos(theta);
965         double sinTheta = FastMath.sin(theta);
966         FieldRotation<DerivativeStructure> r    = new FieldRotation<>(createAxis(kx, ky, kz),
967                                                                       createAngle(theta),
968                                                                       RotationConvention.VECTOR_OPERATOR);
969         Vector3D a      = new Vector3D(kx / n, ky / n, kz / n);
970 
971         // Jacobian of the normalized rotation axis a with respect to the Cartesian vector k
972         RealMatrix dadk = MatrixUtils.createRealMatrix(new double[][] {
973             { (ky * ky + kz * kz) / ( n * n2),            -kx * ky / ( n * n2),            -kx * kz / ( n * n2) },
974             {            -kx * ky / ( n * n2), (kx * kx + kz * kz) / ( n * n2),            -ky * kz / ( n * n2) },
975             {            -kx * kz / ( n * n2),            -ky * kz / ( n * n2), (kx * kx + ky * ky) / ( n * n2) }
976         });
977 
978         for (double x = -0.9; x < 0.9; x += 0.2) {
979             for (double y = -0.9; y < 0.9; y += 0.2) {
980                 for (double z = -0.9; z < 0.9; z += 0.2) {
981                     Vector3D   u = new Vector3D(x, y, z);
982                     FieldVector3D<DerivativeStructure> v = r.applyTo(createVector(x, y, z));
983 
984                     // explicit formula for rotation of vector u around axis a with angle theta
985                     double dot     = Vector3D.dotProduct(u, a);
986                     Vector3D cross = Vector3D.crossProduct(a, u);
987                     double c1      = 1 - cosTheta;
988                     double c2      = c1 * dot;
989                     Vector3D rt    = new Vector3D(cosTheta, u, c2, a, sinTheta, cross);
990                     assertEquals(rt.getX(), v.getX().getReal(), eps);
991                     assertEquals(rt.getY(), v.getY().getReal(), eps);
992                     assertEquals(rt.getZ(), v.getZ().getReal(), eps);
993 
994                     // Jacobian of the image v = r(u) with respect to rotation axis a
995                     // (analytical differentiation of the explicit formula)
996                     RealMatrix dvda = MatrixUtils.createRealMatrix(new double[][] {
997                         { c1 * x * a.getX() + c2,           c1 * y * a.getX() + sinTheta * z, c1 * z * a.getX() - sinTheta * y },
998                         { c1 * x * a.getY() - sinTheta * z, c1 * y * a.getY() + c2,           c1 * z * a.getY() + sinTheta * x },
999                         { c1 * x * a.getZ() + sinTheta * y, c1 * y * a.getZ() - sinTheta * x, c1 * z * a.getZ() + c2           }
1000                     });
1001 
1002                     // compose Jacobians
1003                     RealMatrix dvdk = dvda.multiply(dadk);
1004 
1005                     // derivatives with respect to un-normalized axis
1006                     assertEquals(dvdk.getEntry(0, 0), v.getX().getPartialDerivative(1, 0, 0, 0), eps);
1007                     assertEquals(dvdk.getEntry(0, 1), v.getX().getPartialDerivative(0, 1, 0, 0), eps);
1008                     assertEquals(dvdk.getEntry(0, 2), v.getX().getPartialDerivative(0, 0, 1, 0), eps);
1009                     assertEquals(dvdk.getEntry(1, 0), v.getY().getPartialDerivative(1, 0, 0, 0), eps);
1010                     assertEquals(dvdk.getEntry(1, 1), v.getY().getPartialDerivative(0, 1, 0, 0), eps);
1011                     assertEquals(dvdk.getEntry(1, 2), v.getY().getPartialDerivative(0, 0, 1, 0), eps);
1012                     assertEquals(dvdk.getEntry(2, 0), v.getZ().getPartialDerivative(1, 0, 0, 0), eps);
1013                     assertEquals(dvdk.getEntry(2, 1), v.getZ().getPartialDerivative(0, 1, 0, 0), eps);
1014                     assertEquals(dvdk.getEntry(2, 2), v.getZ().getPartialDerivative(0, 0, 1, 0), eps);
1015 
1016                     // derivative with respect to rotation angle
1017                     // (analytical differentiation of the explicit formula)
1018                     Vector3D dvdTheta =
1019                             new Vector3D(-sinTheta, u, sinTheta * dot, a, cosTheta, cross);
1020                     assertEquals(dvdTheta.getX(), v.getX().getPartialDerivative(0, 0, 0, 1), eps);
1021                     assertEquals(dvdTheta.getY(), v.getY().getPartialDerivative(0, 0, 0, 1), eps);
1022                     assertEquals(dvdTheta.getZ(), v.getZ().getPartialDerivative(0, 0, 0, 1), eps);
1023 
1024                 }
1025             }
1026         }
1027      }
1028 
1029     @Test
1030     void testArray() throws MathIllegalArgumentException {
1031 
1032         FieldRotation<DerivativeStructure> r = new FieldRotation<>(createAxis(2, -3, 5),
1033                                                                    createAngle(1.7),
1034                                                                    RotationConvention.VECTOR_OPERATOR);
1035 
1036         for (double x = -0.9; x < 0.9; x += 0.2) {
1037             for (double y = -0.9; y < 0.9; y += 0.2) {
1038                 for (double z = -0.9; z < 0.9; z += 0.2) {
1039                     FieldVector3D<DerivativeStructure> u = createVector(x, y, z);
1040                     FieldVector3D<DerivativeStructure> v = r.applyTo(u);
1041                     DerivativeStructure[] out = new DerivativeStructure[3];
1042                     r.applyTo(new DerivativeStructure[] { u.getX(), u.getY(), u.getZ() }, out);
1043                     assertEquals(v.getX().getReal(), out[0].getReal(), 1.0e-10);
1044                     assertEquals(v.getY().getReal(), out[1].getReal(), 1.0e-10);
1045                     assertEquals(v.getZ().getReal(), out[2].getReal(), 1.0e-10);
1046                     r.applyInverseTo(out, out);
1047                     assertEquals(u.getX().getReal(), out[0].getReal(), 1.0e-10);
1048                     assertEquals(u.getY().getReal(), out[1].getReal(), 1.0e-10);
1049                     assertEquals(u.getZ().getReal(), out[2].getReal(), 1.0e-10);
1050                 }
1051             }
1052         }
1053 
1054     }
1055 
1056     @Test
1057     void testApplyInverseTo() throws MathIllegalArgumentException {
1058 
1059         DerivativeStructure[] in      = new DerivativeStructure[3];
1060         DerivativeStructure[] out     = new DerivativeStructure[3];
1061         DerivativeStructure[] rebuilt = new DerivativeStructure[3];
1062         FieldRotation<DerivativeStructure> r = new FieldRotation<>(createVector(2, -3, 5),
1063                                                                    createAngle(1.7),
1064                                                                    RotationConvention.VECTOR_OPERATOR);
1065         for (double lambda = 0; lambda < 6.2; lambda += 0.2) {
1066             for (double phi = -1.55; phi < 1.55; phi += 0.2) {
1067                 FieldVector3D<DerivativeStructure> u = createVector(FastMath.cos(lambda) * FastMath.cos(phi),
1068                                           FastMath.sin(lambda) * FastMath.cos(phi),
1069                                           FastMath.sin(phi));
1070                 r.applyInverseTo(r.applyTo(u));
1071                 checkVector(u, r.applyInverseTo(r.applyTo(u)));
1072                 checkVector(u, r.applyTo(r.applyInverseTo(u)));
1073                 in[0] = u.getX();
1074                 in[1] = u.getY();
1075                 in[2] = u.getZ();
1076                 r.applyTo(in, out);
1077                 r.applyInverseTo(out, rebuilt);
1078                 assertEquals(in[0].getReal(), rebuilt[0].getReal(), 1.0e-12);
1079                 assertEquals(in[1].getReal(), rebuilt[1].getReal(), 1.0e-12);
1080                 assertEquals(in[2].getReal(), rebuilt[2].getReal(), 1.0e-12);
1081             }
1082         }
1083 
1084         r = createRotation(1, 0, 0, 0, false);
1085         for (double lambda = 0; lambda < 6.2; lambda += 0.2) {
1086             for (double phi = -1.55; phi < 1.55; phi += 0.2) {
1087                 FieldVector3D<DerivativeStructure> u = createVector(FastMath.cos(lambda) * FastMath.cos(phi),
1088                                                                     FastMath.sin(lambda) * FastMath.cos(phi),
1089                                                                     FastMath.sin(phi));
1090                 checkVector(u, r.applyInverseTo(r.applyTo(u)));
1091                 checkVector(u, r.applyTo(r.applyInverseTo(u)));
1092             }
1093         }
1094 
1095         r = new FieldRotation<>(createVector(0, 0, 1), createAngle(FastMath.PI), RotationConvention.VECTOR_OPERATOR);
1096         for (double lambda = 0; lambda < 6.2; lambda += 0.2) {
1097             for (double phi = -1.55; phi < 1.55; phi += 0.2) {
1098                 FieldVector3D<DerivativeStructure> u = createVector(FastMath.cos(lambda) * FastMath.cos(phi),
1099                                           FastMath.sin(lambda) * FastMath.cos(phi),
1100                                           FastMath.sin(phi));
1101                 checkVector(u, r.applyInverseTo(r.applyTo(u)));
1102                 checkVector(u, r.applyTo(r.applyInverseTo(u)));
1103             }
1104         }
1105 
1106     }
1107 
1108     @Test
1109     void testIssue639() throws MathRuntimeException{
1110         FieldVector3D<DerivativeStructure> u1 = createVector(-1321008684645961.0 /  268435456.0,
1111                                    -5774608829631843.0 /  268435456.0,
1112                                    -3822921525525679.0 / 4294967296.0);
1113         FieldVector3D<DerivativeStructure> u2 =createVector( -5712344449280879.0 /    2097152.0,
1114                                    -2275058564560979.0 /    1048576.0,
1115                                    4423475992255071.0 /      65536.0);
1116         FieldRotation<DerivativeStructure> rot = new FieldRotation<>(u1, u2, createVector(1, 0, 0),createVector(0, 0, 1));
1117         assertEquals( 0.6228370359608200639829222, rot.getQ0().getReal(), 1.0e-15);
1118         assertEquals( 0.0257707621456498790029987, rot.getQ1().getReal(), 1.0e-15);
1119         assertEquals(-0.0000000002503012255839931, rot.getQ2().getReal(), 1.0e-15);
1120         assertEquals(-0.7819270390861109450724902, rot.getQ3().getReal(), 1.0e-15);
1121     }
1122 
1123     @Test
1124     void testIssue801() throws MathRuntimeException {
1125         FieldVector3D<DerivativeStructure> u1 = createVector(0.9999988431610581, -0.0015210774290851095, 0.0);
1126         FieldVector3D<DerivativeStructure> u2 = createVector(0.0, 0.0, 1.0);
1127 
1128         FieldVector3D<DerivativeStructure> v1 = createVector(0.9999999999999999, 0.0, 0.0);
1129         FieldVector3D<DerivativeStructure> v2 = createVector(0.0, 0.0, -1.0);
1130 
1131         FieldRotation<DerivativeStructure> quat = new FieldRotation<>(u1, u2, v1, v2);
1132         double q2 = quat.getQ0().getReal() * quat.getQ0().getReal() +
1133                     quat.getQ1().getReal() * quat.getQ1().getReal() +
1134                     quat.getQ2().getReal() * quat.getQ2().getReal() +
1135                     quat.getQ3().getReal() * quat.getQ3().getReal();
1136         assertEquals(1.0, q2, 1.0e-14);
1137         assertEquals(0.0, FieldVector3D.angle(v1, quat.applyTo(u1)).getReal(), 1.0e-14);
1138         assertEquals(0.0, FieldVector3D.angle(v2, quat.applyTo(u2)).getReal(), 1.0e-14);
1139 
1140     }
1141 
1142     private void checkAngle(DerivativeStructure a1, double a2) {
1143         assertEquals(a1.getReal(), MathUtils.normalizeAngle(a2, a1.getReal()), 1.0e-10);
1144     }
1145 
1146     private void checkRotationDS(FieldRotation<DerivativeStructure> r, double q0, double q1, double q2, double q3) {
1147         FieldRotation<DerivativeStructure> rPrime = createRotation(q0, q1, q2, q3, false);
1148         assertEquals(0, FieldRotation.distance(r, rPrime).getReal(), 1.0e-12);
1149     }
1150 
1151     private FieldRotation<DerivativeStructure> createRotation(double q0, double q1, double q2, double q3,
1152                                       boolean needsNormalization) {
1153         DSFactory factory = new DSFactory(4, 1);
1154         return new FieldRotation<>(factory.variable(0, q0),
1155                                    factory.variable(1, q1),
1156                                    factory.variable(2, q2),
1157                                    factory.variable(3, q3),
1158                                    needsNormalization);
1159     }
1160 
1161     private FieldRotation<DerivativeStructure> createRotation(double[][] m, double threshold) {
1162         DSFactory factory = new DSFactory(4, 1);
1163         DerivativeStructure[][] mds = new DerivativeStructure[m.length][m[0].length];
1164         int index = 0;
1165         for (int i = 0; i < m.length; ++i) {
1166             for (int j = 0; j < m[i].length; ++j) {
1167                 mds[i][j] = factory.variable(index, m[i][j]);
1168                 index = (index + 1) % 4;
1169             }
1170         }
1171         return new FieldRotation<>(mds, threshold);
1172     }
1173 
1174     private FieldVector3D<DerivativeStructure> createVector(double x, double y, double z) {
1175         DSFactory factory = new DSFactory(4, 1);
1176         return new FieldVector3D<>(factory.constant(x), factory.constant(y),  factory.constant(z));
1177     }
1178 
1179     private FieldVector3D<DerivativeStructure> createAxis(double x, double y, double z) {
1180         DSFactory factory = new DSFactory(4, 1);
1181         return new FieldVector3D<>(factory.variable(0, x), factory.variable(1, y), factory.variable(2, z));
1182     }
1183 
1184     private DerivativeStructure createAngle(double alpha) {
1185         DSFactory factory = new DSFactory(4, 1);
1186         return factory.variable(3, alpha);
1187     }
1188 
1189     private void checkVector(FieldVector3D<DerivativeStructure> u, FieldVector3D<DerivativeStructure> v) {
1190         assertEquals(u.getX().getReal(), v.getX().getReal(), 1.0e-12);
1191         assertEquals(u.getY().getReal(), v.getY().getReal(), 1.0e-12);
1192         assertEquals(u.getZ().getReal(), v.getZ().getReal(), 1.0e-12);
1193     }
1194 
1195 }