1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.utils;
18
19 import org.hipparchus.Field;
20 import org.hipparchus.CalculusFieldElement;
21 import org.hipparchus.analysis.differentiation.FDSFactory;
22 import org.hipparchus.analysis.differentiation.FieldDerivative;
23 import org.hipparchus.analysis.differentiation.FieldDerivativeStructure;
24 import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
25 import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2;
26 import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
27 import org.hipparchus.analysis.differentiation.UnivariateDerivative2;
28 import org.hipparchus.exception.LocalizedCoreFormats;
29 import org.hipparchus.exception.MathIllegalArgumentException;
30 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
31 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
32 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
33 import org.hipparchus.linear.FieldDecompositionSolver;
34 import org.hipparchus.linear.FieldMatrix;
35 import org.hipparchus.linear.FieldQRDecomposition;
36 import org.hipparchus.linear.FieldVector;
37 import org.hipparchus.linear.MatrixUtils;
38 import org.hipparchus.util.MathArrays;
39 import org.orekit.errors.OrekitException;
40 import org.orekit.errors.OrekitMessages;
41 import org.orekit.time.FieldTimeShiftable;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public class FieldAngularCoordinates<T extends CalculusFieldElement<T>>
61 implements FieldTimeShiftable<FieldAngularCoordinates<T>, T> {
62
63
64 private final FieldRotation<T> rotation;
65
66
67 private final FieldVector3D<T> rotationRate;
68
69
70 private final FieldVector3D<T> rotationAcceleration;
71
72
73
74
75
76 public FieldAngularCoordinates(final FieldRotation<T> rotation,
77 final FieldVector3D<T> rotationRate) {
78 this(rotation, rotationRate, FieldVector3D.getZero(rotation.getQ0().getField()));
79 }
80
81
82
83
84
85
86 public FieldAngularCoordinates(final FieldRotation<T> rotation,
87 final FieldVector3D<T> rotationRate,
88 final FieldVector3D<T> rotationAcceleration) {
89 this.rotation = rotation;
90 this.rotationRate = rotationRate;
91 this.rotationAcceleration = rotationAcceleration;
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public FieldAngularCoordinates(final FieldPVCoordinates<T> u1, final FieldPVCoordinates<T> u2,
115 final FieldPVCoordinates<T> v1, final FieldPVCoordinates<T> v2,
116 final double tolerance) {
117
118 try {
119
120 rotation = new FieldRotation<>(u1.getPosition(), u2.getPosition(),
121 v1.getPosition(), v2.getPosition());
122
123
124
125
126 final FieldVector3D<T> ru1Dot = rotation.applyTo(u1.getVelocity());
127 final FieldVector3D<T> ru2Dot = rotation.applyTo(u2.getVelocity());
128
129
130 rotationRate = inverseCrossProducts(v1.getPosition(), ru1Dot.subtract(v1.getVelocity()),
131 v2.getPosition(), ru2Dot.subtract(v2.getVelocity()),
132 tolerance);
133
134
135
136
137
138 final FieldVector3D<T> ru1DotDot = rotation.applyTo(u1.getAcceleration());
139 final FieldVector3D<T> oDotv1 = FieldVector3D.crossProduct(rotationRate, v1.getVelocity());
140 final FieldVector3D<T> oov1 = FieldVector3D.crossProduct(rotationRate, rotationRate.crossProduct(v1.getPosition()));
141 final FieldVector3D<T> c1 = new FieldVector3D<>(1, ru1DotDot, -2, oDotv1, -1, oov1, -1, v1.getAcceleration());
142 final FieldVector3D<T> ru2DotDot = rotation.applyTo(u2.getAcceleration());
143 final FieldVector3D<T> oDotv2 = FieldVector3D.crossProduct(rotationRate, v2.getVelocity());
144 final FieldVector3D<T> oov2 = FieldVector3D.crossProduct(rotationRate, rotationRate.crossProduct( v2.getPosition()));
145 final FieldVector3D<T> c2 = new FieldVector3D<>(1, ru2DotDot, -2, oDotv2, -1, oov2, -1, v2.getAcceleration());
146 rotationAcceleration = inverseCrossProducts(v1.getPosition(), c1, v2.getPosition(), c2, tolerance);
147
148 } catch (MathIllegalArgumentException miae) {
149 throw new OrekitException(miae);
150 }
151
152 }
153
154
155
156
157
158 public FieldAngularCoordinates(final Field<T> field, final AngularCoordinates ang) {
159 this.rotation = new FieldRotation<>(field, ang.getRotation());
160 this.rotationRate = new FieldVector3D<>(field, ang.getRotationRate());
161 this.rotationAcceleration = new FieldVector3D<>(field, ang.getRotationAcceleration());
162 }
163
164
165
166
167
168
169
170
171
172
173 public <U extends FieldDerivative<T, U>> FieldAngularCoordinates(final FieldRotation<U> r) {
174
175 final T q0 = r.getQ0().getValue();
176 final T q1 = r.getQ1().getValue();
177 final T q2 = r.getQ2().getValue();
178 final T q3 = r.getQ3().getValue();
179
180 rotation = new FieldRotation<>(q0, q1, q2, q3, false);
181 if (r.getQ0().getOrder() >= 1) {
182 final T q0Dot = r.getQ0().getPartialDerivative(1);
183 final T q1Dot = r.getQ1().getPartialDerivative(1);
184 final T q2Dot = r.getQ2().getPartialDerivative(1);
185 final T q3Dot = r.getQ3().getPartialDerivative(1);
186 rotationRate =
187 new FieldVector3D<>(q0.linearCombination(q1.negate(), q0Dot, q0, q1Dot,
188 q3, q2Dot, q2.negate(), q3Dot).multiply(2),
189 q0.linearCombination(q2.negate(), q0Dot, q3.negate(), q1Dot,
190 q0, q2Dot, q1, q3Dot).multiply(2),
191 q0.linearCombination(q3.negate(), q0Dot, q2, q1Dot,
192 q1.negate(), q2Dot, q0, q3Dot).multiply(2));
193 if (r.getQ0().getOrder() >= 2) {
194 final T q0DotDot = r.getQ0().getPartialDerivative(2);
195 final T q1DotDot = r.getQ1().getPartialDerivative(2);
196 final T q2DotDot = r.getQ2().getPartialDerivative(2);
197 final T q3DotDot = r.getQ3().getPartialDerivative(2);
198 rotationAcceleration =
199 new FieldVector3D<>(q0.linearCombination(q1.negate(), q0DotDot, q0, q1DotDot,
200 q3, q2DotDot, q2.negate(), q3DotDot).multiply(2),
201 q0.linearCombination(q2.negate(), q0DotDot, q3.negate(), q1DotDot,
202 q0, q2DotDot, q1, q3DotDot).multiply(2),
203 q0.linearCombination(q3.negate(), q0DotDot, q2, q1DotDot,
204 q1.negate(), q2DotDot, q0, q3DotDot).multiply(2));
205 } else {
206 rotationAcceleration = FieldVector3D.getZero(q0.getField());
207 }
208 } else {
209 rotationRate = FieldVector3D.getZero(q0.getField());
210 rotationAcceleration = FieldVector3D.getZero(q0.getField());
211 }
212
213 }
214
215
216
217
218
219
220
221 public static <T extends CalculusFieldElement<T>> FieldAngularCoordinates<T> getIdentity(final Field<T> field) {
222 return new FieldAngularCoordinates<>(field, AngularCoordinates.IDENTITY);
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243 private static <T extends CalculusFieldElement<T>> FieldVector3D<T> inverseCrossProducts(final FieldVector3D<T> v1, final FieldVector3D<T> c1,
244 final FieldVector3D<T> v2, final FieldVector3D<T> c2,
245 final double tolerance)
246 throws MathIllegalArgumentException {
247
248 final T v12 = v1.getNormSq();
249 final T v1n = v12.sqrt();
250 final T v22 = v2.getNormSq();
251 final T v2n = v22.sqrt();
252 final T threshold;
253 if (v1n.getReal() >= v2n.getReal()) {
254 threshold = v1n.multiply(tolerance);
255 }
256 else {
257 threshold = v2n.multiply(tolerance);
258 }
259 FieldVector3D<T> omega = null;
260
261 try {
262
263 final FieldMatrix<T> m = MatrixUtils.createFieldMatrix(v12.getField(), 6, 3);
264 m.setEntry(0, 1, v1.getZ());
265 m.setEntry(0, 2, v1.getY().negate());
266 m.setEntry(1, 0, v1.getZ().negate());
267 m.setEntry(1, 2, v1.getX());
268 m.setEntry(2, 0, v1.getY());
269 m.setEntry(2, 1, v1.getX().negate());
270 m.setEntry(3, 1, v2.getZ());
271 m.setEntry(3, 2, v2.getY().negate());
272 m.setEntry(4, 0, v2.getZ().negate());
273 m.setEntry(4, 2, v2.getX());
274 m.setEntry(5, 0, v2.getY());
275 m.setEntry(5, 1, v2.getX().negate());
276
277 final T[] kk = MathArrays.buildArray(v2n.getField(), 6);
278 kk[0] = c1.getX();
279 kk[1] = c1.getY();
280 kk[2] = c1.getZ();
281 kk[3] = c2.getX();
282 kk[4] = c2.getY();
283 kk[5] = c2.getZ();
284 final FieldVector<T> rhs = MatrixUtils.createFieldVector(kk);
285
286
287 final FieldDecompositionSolver<T> solver = new FieldQRDecomposition<>(m).getSolver();
288 final FieldVector<T> v = solver.solve(rhs);
289 omega = new FieldVector3D<>(v.getEntry(0), v.getEntry(1), v.getEntry(2));
290
291 } catch (MathIllegalArgumentException miae) {
292 if (miae.getSpecifier() == LocalizedCoreFormats.SINGULAR_MATRIX) {
293
294
295 final T c12 = c1.getNormSq();
296 final T c1n = c12.sqrt();
297 final T c22 = c2.getNormSq();
298 final T c2n = c22.sqrt();
299 if (c1n.getReal() <= threshold.getReal() && c2n.getReal() <= threshold.getReal()) {
300
301 return new FieldVector3D<>(v12.getField().getZero(), v12.getField().getZero(), v12.getField().getZero());
302 } else if (v1n.getReal() <= threshold.getReal() && c1n.getReal() >= threshold.getReal()) {
303
304 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE,
305 c1n.getReal(), 0, true);
306 } else if (v2n.getReal() <= threshold.getReal() && c2n.getReal() >= threshold.getReal()) {
307
308 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE,
309 c2n.getReal(), 0, true);
310 } else if (v1.crossProduct(v1).getNorm().getReal() <= threshold.getReal() && v12.getReal() > threshold.getReal()) {
311
312
313 omega = new FieldVector3D<>(v12.reciprocal(), v1.crossProduct(c1));
314 } else {
315 throw miae;
316 }
317 } else {
318 throw miae;
319 }
320 }
321
322 final T d1 = FieldVector3D.distance(omega.crossProduct(v1), c1);
323 if (d1.getReal() > threshold.getReal()) {
324 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, 0, true);
325 }
326
327 final T d2 = FieldVector3D.distance(omega.crossProduct(v2), c2);
328 if (d2.getReal() > threshold.getReal()) {
329 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, 0, true);
330 }
331
332 return omega;
333
334 }
335
336
337
338
339
340
341
342
343
344
345 public FieldRotation<FieldDerivativeStructure<T>> toDerivativeStructureRotation(final int order) {
346
347
348 final T q0 = rotation.getQ0();
349 final T q1 = rotation.getQ1();
350 final T q2 = rotation.getQ2();
351 final T q3 = rotation.getQ3();
352
353
354 final T oX = rotationRate.getX();
355 final T oY = rotationRate.getY();
356 final T oZ = rotationRate.getZ();
357 final T q0Dot = q0.linearCombination(q1.negate(), oX, q2.negate(), oY, q3.negate(), oZ).multiply(0.5);
358 final T q1Dot = q0.linearCombination(q0, oX, q3.negate(), oY, q2, oZ).multiply(0.5);
359 final T q2Dot = q0.linearCombination(q3, oX, q0, oY, q1.negate(), oZ).multiply(0.5);
360 final T q3Dot = q0.linearCombination(q2.negate(), oX, q1, oY, q0, oZ).multiply(0.5);
361
362
363 final T oXDot = rotationAcceleration.getX();
364 final T oYDot = rotationAcceleration.getY();
365 final T oZDot = rotationAcceleration.getZ();
366 final T q0DotDot = q0.linearCombination(array6(q1, q2, q3, q1Dot, q2Dot, q3Dot),
367 array6(oXDot, oYDot, oZDot, oX, oY, oZ)).multiply(-0.5);
368 final T q1DotDot = q0.linearCombination(array6(q0, q2, q3.negate(), q0Dot, q2Dot, q3Dot.negate()),
369 array6(oXDot, oZDot, oYDot, oX, oZ, oY)).multiply(0.5);
370 final T q2DotDot = q0.linearCombination(array6(q0, q3, q1.negate(), q0Dot, q3Dot, q1Dot.negate()),
371 array6(oYDot, oXDot, oZDot, oY, oX, oZ)).multiply(0.5);
372 final T q3DotDot = q0.linearCombination(array6(q0, q1, q2.negate(), q0Dot, q1Dot, q2Dot.negate()),
373 array6(oZDot, oYDot, oXDot, oZ, oY, oX)).multiply(0.5);
374
375 final FDSFactory<T> factory;
376 final FieldDerivativeStructure<T> q0DS;
377 final FieldDerivativeStructure<T> q1DS;
378 final FieldDerivativeStructure<T> q2DS;
379 final FieldDerivativeStructure<T> q3DS;
380 switch (order) {
381 case 0 :
382 factory = new FDSFactory<>(q0.getField(), 1, order);
383 q0DS = factory.build(q0);
384 q1DS = factory.build(q1);
385 q2DS = factory.build(q2);
386 q3DS = factory.build(q3);
387 break;
388 case 1 :
389 factory = new FDSFactory<>(q0.getField(), 1, order);
390 q0DS = factory.build(q0, q0Dot);
391 q1DS = factory.build(q1, q1Dot);
392 q2DS = factory.build(q2, q2Dot);
393 q3DS = factory.build(q3, q3Dot);
394 break;
395 case 2 :
396 factory = new FDSFactory<>(q0.getField(), 1, order);
397 q0DS = factory.build(q0, q0Dot, q0DotDot);
398 q1DS = factory.build(q1, q1Dot, q1DotDot);
399 q2DS = factory.build(q2, q2Dot, q2DotDot);
400 q3DS = factory.build(q3, q3Dot, q3DotDot);
401 break;
402 default :
403 throw new OrekitException(OrekitMessages.OUT_OF_RANGE_DERIVATION_ORDER, order);
404 }
405
406 return new FieldRotation<>(q0DS, q1DS, q2DS, q3DS, false);
407
408 }
409
410
411
412
413
414
415
416
417 public FieldRotation<FieldUnivariateDerivative1<T>> toUnivariateDerivative1Rotation() {
418
419
420 final T q0 = rotation.getQ0();
421 final T q1 = rotation.getQ1();
422 final T q2 = rotation.getQ2();
423 final T q3 = rotation.getQ3();
424
425
426 final T oX = rotationRate.getX();
427 final T oY = rotationRate.getY();
428 final T oZ = rotationRate.getZ();
429 final T q0Dot = q0.linearCombination(q1.negate(), oX, q2.negate(), oY, q3.negate(), oZ).multiply(0.5);
430 final T q1Dot = q0.linearCombination(q0, oX, q3.negate(), oY, q2, oZ).multiply(0.5);
431 final T q2Dot = q0.linearCombination(q3, oX, q0, oY, q1.negate(), oZ).multiply(0.5);
432 final T q3Dot = q0.linearCombination(q2.negate(), oX, q1, oY, q0, oZ).multiply(0.5);
433
434 final FieldUnivariateDerivative1<T> q0UD = new FieldUnivariateDerivative1<>(q0, q0Dot);
435 final FieldUnivariateDerivative1<T> q1UD = new FieldUnivariateDerivative1<>(q1, q1Dot);
436 final FieldUnivariateDerivative1<T> q2UD = new FieldUnivariateDerivative1<>(q2, q2Dot);
437 final FieldUnivariateDerivative1<T> q3UD = new FieldUnivariateDerivative1<>(q3, q3Dot);
438
439 return new FieldRotation<>(q0UD, q1UD, q2UD, q3UD, false);
440
441 }
442
443
444
445
446
447
448
449
450 public FieldRotation<FieldUnivariateDerivative2<T>> toUnivariateDerivative2Rotation() {
451
452
453 final T q0 = rotation.getQ0();
454 final T q1 = rotation.getQ1();
455 final T q2 = rotation.getQ2();
456 final T q3 = rotation.getQ3();
457
458
459 final T oX = rotationRate.getX();
460 final T oY = rotationRate.getY();
461 final T oZ = rotationRate.getZ();
462 final T q0Dot = q0.linearCombination(q1.negate(), oX, q2.negate(), oY, q3.negate(), oZ).multiply(0.5);
463 final T q1Dot = q0.linearCombination(q0, oX, q3.negate(), oY, q2, oZ).multiply(0.5);
464 final T q2Dot = q0.linearCombination(q3, oX, q0, oY, q1.negate(), oZ).multiply(0.5);
465 final T q3Dot = q0.linearCombination(q2.negate(), oX, q1, oY, q0, oZ).multiply(0.5);
466
467
468 final T oXDot = rotationAcceleration.getX();
469 final T oYDot = rotationAcceleration.getY();
470 final T oZDot = rotationAcceleration.getZ();
471 final T q0DotDot = q0.linearCombination(array6(q1, q2, q3, q1Dot, q2Dot, q3Dot),
472 array6(oXDot, oYDot, oZDot, oX, oY, oZ)).multiply(-0.5);
473 final T q1DotDot = q0.linearCombination(array6(q0, q2, q3.negate(), q0Dot, q2Dot, q3Dot.negate()),
474 array6(oXDot, oZDot, oYDot, oX, oZ, oY)).multiply(0.5);
475 final T q2DotDot = q0.linearCombination(array6(q0, q3, q1.negate(), q0Dot, q3Dot, q1Dot.negate()),
476 array6(oYDot, oXDot, oZDot, oY, oX, oZ)).multiply(0.5);
477 final T q3DotDot = q0.linearCombination(array6(q0, q1, q2.negate(), q0Dot, q1Dot, q2Dot.negate()),
478 array6(oZDot, oYDot, oXDot, oZ, oY, oX)).multiply(0.5);
479
480 final FieldUnivariateDerivative2<T> q0UD = new FieldUnivariateDerivative2<>(q0, q0Dot, q0DotDot);
481 final FieldUnivariateDerivative2<T> q1UD = new FieldUnivariateDerivative2<>(q1, q1Dot, q1DotDot);
482 final FieldUnivariateDerivative2<T> q2UD = new FieldUnivariateDerivative2<>(q2, q2Dot, q2DotDot);
483 final FieldUnivariateDerivative2<T> q3UD = new FieldUnivariateDerivative2<>(q3, q3Dot, q3DotDot);
484
485 return new FieldRotation<>(q0UD, q1UD, q2UD, q3UD, false);
486
487 }
488
489
490
491
492
493
494
495
496
497
498
499 private T[] array6(final T e1, final T e2, final T e3, final T e4, final T e5, final T e6) {
500 final T[] array = MathArrays.buildArray(e1.getField(), 6);
501 array[0] = e1;
502 array[1] = e2;
503 array[2] = e3;
504 array[3] = e4;
505 array[4] = e5;
506 array[5] = e6;
507 return array;
508 }
509
510
511
512
513
514
515
516
517
518
519 public static <T extends CalculusFieldElement<T>>
520 FieldVector3D<T> estimateRate(final FieldRotation<T> start,
521 final FieldRotation<T> end,
522 final double dt) {
523 return estimateRate(start, end, start.getQ0().getField().getZero().newInstance(dt));
524 }
525
526
527
528
529
530
531
532
533
534
535 public static <T extends CalculusFieldElement<T>>
536 FieldVector3D<T> estimateRate(final FieldRotation<T> start,
537 final FieldRotation<T> end,
538 final T dt) {
539 final FieldRotation<T> evolution = start.compose(end.revert(), RotationConvention.VECTOR_OPERATOR);
540 return new FieldVector3D<>(evolution.getAngle().divide(dt),
541 evolution.getAxis(RotationConvention.VECTOR_OPERATOR));
542 }
543
544
545
546
547
548
549
550
551
552 public FieldAngularCoordinates<T> revert() {
553 return new FieldAngularCoordinates<>(rotation.revert(),
554 rotation.applyInverseTo(rotationRate.negate()),
555 rotation.applyInverseTo(rotationAcceleration.negate()));
556 }
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571 public FieldRotation<T> rotationShiftedBy(final T dt) {
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587 final T rate = rotationRate.getNorm();
588 final FieldRotation<T> rateContribution = (rate.getReal() == 0.0) ?
589 FieldRotation.getIdentity(dt.getField()) :
590 new FieldRotation<>(rotationRate, rate.multiply(dt), RotationConvention.FRAME_TRANSFORM);
591
592
593 final FieldRotation<T> linearPart =
594 rateContribution.compose(rotation, RotationConvention.VECTOR_OPERATOR);
595
596 final T acc = rotationAcceleration.getNorm();
597 if (acc.getReal() == 0.0) {
598
599 return linearPart;
600 }
601
602
603
604
605
606 final FieldRotation<T> quadraticContribution =
607 new FieldRotation<>(rotationAcceleration,
608 acc.multiply(dt.square()).multiply(0.5),
609 RotationConvention.FRAME_TRANSFORM);
610
611
612
613
614
615 return quadraticContribution
616 .compose(linearPart, RotationConvention.VECTOR_OPERATOR);
617
618 }
619
620
621
622
623
624
625
626
627
628
629
630 @Override
631 public FieldAngularCoordinates<T> shiftedBy(final double dt) {
632 return shiftedBy(rotation.getQ0().getField().getZero().newInstance(dt));
633 }
634
635
636
637
638
639
640
641
642
643
644
645 @Override
646 public FieldAngularCoordinates<T> shiftedBy(final T dt) {
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662 final T rate = rotationRate.getNorm();
663 final T zero = rate.getField().getZero();
664 final T one = rate.getField().getOne();
665 final FieldRotation<T> rateContribution = (rate.getReal() == 0.0) ?
666 new FieldRotation<>(one, zero, zero, zero, false) :
667 new FieldRotation<>(rotationRate,
668 rate.multiply(dt),
669 RotationConvention.FRAME_TRANSFORM);
670
671
672 final FieldAngularCoordinates<T> linearPart =
673 new FieldAngularCoordinates<>(rateContribution.compose(rotation, RotationConvention.VECTOR_OPERATOR),
674 rotationRate);
675
676 final T acc = rotationAcceleration.getNorm();
677 if (acc.getReal() == 0.0) {
678
679 return linearPart;
680 }
681
682
683
684
685
686 final FieldAngularCoordinates<T> quadraticContribution =
687 new FieldAngularCoordinates<>(new FieldRotation<>(rotationAcceleration,
688 acc.multiply(dt.square().multiply(0.5)),
689 RotationConvention.FRAME_TRANSFORM),
690 new FieldVector3D<>(dt, rotationAcceleration),
691 rotationAcceleration);
692
693
694
695
696
697 return quadraticContribution.addOffset(linearPart);
698
699 }
700
701
702
703
704 public FieldRotation<T> getRotation() {
705 return rotation;
706 }
707
708
709
710
711 public FieldVector3D<T> getRotationRate() {
712 return rotationRate;
713 }
714
715
716
717
718 public FieldVector3D<T> getRotationAcceleration() {
719 return rotationAcceleration;
720 }
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740 public FieldAngularCoordinates<T> addOffset(final FieldAngularCoordinates<T> offset) {
741 final FieldVector3D<T> rOmega = rotation.applyTo(offset.rotationRate);
742 final FieldVector3D<T> rOmegaDot = rotation.applyTo(offset.rotationAcceleration);
743 return new FieldAngularCoordinates<>(rotation.compose(offset.rotation, RotationConvention.VECTOR_OPERATOR),
744 rotationRate.add(rOmega),
745 new FieldVector3D<>( 1.0, rotationAcceleration,
746 1.0, rOmegaDot,
747 -1.0, FieldVector3D.crossProduct(rotationRate, rOmega)));
748 }
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768 public FieldAngularCoordinates<T> subtractOffset(final FieldAngularCoordinates<T> offset) {
769 return addOffset(offset.revert());
770 }
771
772
773
774
775 public AngularCoordinates toAngularCoordinates() {
776 return new AngularCoordinates(rotation.toRotation(), rotationRate.toVector3D(),
777 rotationAcceleration.toVector3D());
778 }
779
780
781
782
783
784 public FieldPVCoordinates<T> applyTo(final PVCoordinates pv) {
785
786 final FieldVector3D<T> transformedP = rotation.applyTo(pv.getPosition());
787 final FieldVector3D<T> crossP = FieldVector3D.crossProduct(rotationRate, transformedP);
788 final FieldVector3D<T> transformedV = rotation.applyTo(pv.getVelocity()).subtract(crossP);
789 final FieldVector3D<T> crossV = FieldVector3D.crossProduct(rotationRate, transformedV);
790 final FieldVector3D<T> crossCrossP = FieldVector3D.crossProduct(rotationRate, crossP);
791 final FieldVector3D<T> crossDotP = FieldVector3D.crossProduct(rotationAcceleration, transformedP);
792 final FieldVector3D<T> transformedA = new FieldVector3D<>( 1, rotation.applyTo(pv.getAcceleration()),
793 -2, crossV,
794 -1, crossCrossP,
795 -1, crossDotP);
796
797 return new FieldPVCoordinates<>(transformedP, transformedV, transformedA);
798
799 }
800
801
802
803
804
805 public TimeStampedFieldPVCoordinates<T> applyTo(final TimeStampedPVCoordinates pv) {
806
807 final FieldVector3D<T> transformedP = rotation.applyTo(pv.getPosition());
808 final FieldVector3D<T> crossP = FieldVector3D.crossProduct(rotationRate, transformedP);
809 final FieldVector3D<T> transformedV = rotation.applyTo(pv.getVelocity()).subtract(crossP);
810 final FieldVector3D<T> crossV = FieldVector3D.crossProduct(rotationRate, transformedV);
811 final FieldVector3D<T> crossCrossP = FieldVector3D.crossProduct(rotationRate, crossP);
812 final FieldVector3D<T> crossDotP = FieldVector3D.crossProduct(rotationAcceleration, transformedP);
813 final FieldVector3D<T> transformedA = new FieldVector3D<>( 1, rotation.applyTo(pv.getAcceleration()),
814 -2, crossV,
815 -1, crossCrossP,
816 -1, crossDotP);
817
818 return new TimeStampedFieldPVCoordinates<>(pv.getDate(), transformedP, transformedV, transformedA);
819
820 }
821
822
823
824
825
826
827 public FieldPVCoordinates<T> applyTo(final FieldPVCoordinates<T> pv) {
828
829 final FieldVector3D<T> transformedP = rotation.applyTo(pv.getPosition());
830 final FieldVector3D<T> crossP = FieldVector3D.crossProduct(rotationRate, transformedP);
831 final FieldVector3D<T> transformedV = rotation.applyTo(pv.getVelocity()).subtract(crossP);
832 final FieldVector3D<T> crossV = FieldVector3D.crossProduct(rotationRate, transformedV);
833 final FieldVector3D<T> crossCrossP = FieldVector3D.crossProduct(rotationRate, crossP);
834 final FieldVector3D<T> crossDotP = FieldVector3D.crossProduct(rotationAcceleration, transformedP);
835 final FieldVector3D<T> transformedA = new FieldVector3D<>( 1, rotation.applyTo(pv.getAcceleration()),
836 -2, crossV,
837 -1, crossCrossP,
838 -1, crossDotP);
839
840 return new FieldPVCoordinates<>(transformedP, transformedV, transformedA);
841
842 }
843
844
845
846
847
848
849 public TimeStampedFieldPVCoordinates<T> applyTo(final TimeStampedFieldPVCoordinates<T> pv) {
850
851 final FieldVector3D<T> transformedP = rotation.applyTo(pv.getPosition());
852 final FieldVector3D<T> crossP = FieldVector3D.crossProduct(rotationRate, transformedP);
853 final FieldVector3D<T> transformedV = rotation.applyTo(pv.getVelocity()).subtract(crossP);
854 final FieldVector3D<T> crossV = FieldVector3D.crossProduct(rotationRate, transformedV);
855 final FieldVector3D<T> crossCrossP = FieldVector3D.crossProduct(rotationRate, crossP);
856 final FieldVector3D<T> crossDotP = FieldVector3D.crossProduct(rotationAcceleration, transformedP);
857 final FieldVector3D<T> transformedA = new FieldVector3D<>( 1, rotation.applyTo(pv.getAcceleration()),
858 -2, crossV,
859 -1, crossCrossP,
860 -1, crossDotP);
861
862 return new TimeStampedFieldPVCoordinates<>(pv.getDate(), transformedP, transformedV, transformedA);
863
864 }
865
866
867
868
869
870
871
872
873
874
875
876
877 public T[][] getModifiedRodrigues(final double sign) {
878
879 final T q0 = getRotation().getQ0().multiply(sign);
880 final T q1 = getRotation().getQ1().multiply(sign);
881 final T q2 = getRotation().getQ2().multiply(sign);
882 final T q3 = getRotation().getQ3().multiply(sign);
883 final T oX = getRotationRate().getX();
884 final T oY = getRotationRate().getY();
885 final T oZ = getRotationRate().getZ();
886 final T oXDot = getRotationAcceleration().getX();
887 final T oYDot = getRotationAcceleration().getY();
888 final T oZDot = getRotationAcceleration().getZ();
889
890
891 final T q0Dot = q0.linearCombination(q1.negate(), oX, q2.negate(), oY, q3.negate(), oZ).multiply(0.5);
892 final T q1Dot = q0.linearCombination( q0, oX, q3.negate(), oY, q2, oZ).multiply(0.5);
893 final T q2Dot = q0.linearCombination( q3, oX, q0, oY, q1.negate(), oZ).multiply(0.5);
894 final T q3Dot = q0.linearCombination(q2.negate(), oX, q1, oY, q0, oZ).multiply(0.5);
895
896
897 final T q0DotDot = linearCombination(q1, oXDot, q2, oYDot, q3, oZDot,
898 q1Dot, oX, q2Dot, oY, q3Dot, oZ).
899 multiply(-0.5);
900 final T q1DotDot = linearCombination(q0, oXDot, q2, oZDot, q3.negate(), oYDot,
901 q0Dot, oX, q2Dot, oZ, q3Dot.negate(), oY).
902 multiply(0.5);
903 final T q2DotDot = linearCombination(q0, oYDot, q3, oXDot, q1.negate(), oZDot,
904 q0Dot, oY, q3Dot, oX, q1Dot.negate(), oZ).
905 multiply(0.5);
906 final T q3DotDot = linearCombination(q0, oZDot, q1, oYDot, q2.negate(), oXDot,
907 q0Dot, oZ, q1Dot, oY, q2Dot.negate(), oX).
908 multiply(0.5);
909
910
911
912
913
914 final T inv = q0.add(1).reciprocal();
915 final T mTwoInvQ0Dot = inv.multiply(q0Dot).multiply(-2);
916
917 final T r1 = inv.multiply(q1);
918 final T r2 = inv.multiply(q2);
919 final T r3 = inv.multiply(q3);
920
921 final T mInvR1 = inv.multiply(r1).negate();
922 final T mInvR2 = inv.multiply(r2).negate();
923 final T mInvR3 = inv.multiply(r3).negate();
924
925 final T r1Dot = q0.linearCombination(inv, q1Dot, mInvR1, q0Dot);
926 final T r2Dot = q0.linearCombination(inv, q2Dot, mInvR2, q0Dot);
927 final T r3Dot = q0.linearCombination(inv, q3Dot, mInvR3, q0Dot);
928
929 final T r1DotDot = q0.linearCombination(inv, q1DotDot, mTwoInvQ0Dot, r1Dot, mInvR1, q0DotDot);
930 final T r2DotDot = q0.linearCombination(inv, q2DotDot, mTwoInvQ0Dot, r2Dot, mInvR2, q0DotDot);
931 final T r3DotDot = q0.linearCombination(inv, q3DotDot, mTwoInvQ0Dot, r3Dot, mInvR3, q0DotDot);
932
933 final T[][] rodrigues = MathArrays.buildArray(q0.getField(), 3, 3);
934 rodrigues[0][0] = r1;
935 rodrigues[0][1] = r2;
936 rodrigues[0][2] = r3;
937 rodrigues[1][0] = r1Dot;
938 rodrigues[1][1] = r2Dot;
939 rodrigues[1][2] = r3Dot;
940 rodrigues[2][0] = r1DotDot;
941 rodrigues[2][1] = r2DotDot;
942 rodrigues[2][2] = r3DotDot;
943 return rodrigues;
944
945 }
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965 private T linearCombination(final T a1, final T b1, final T a2, final T b2, final T a3, final T b3,
966 final T a4, final T b4, final T a5, final T b5, final T a6, final T b6) {
967
968 final T[] a = MathArrays.buildArray(a1.getField(), 6);
969 a[0] = a1;
970 a[1] = a2;
971 a[2] = a3;
972 a[3] = a4;
973 a[4] = a5;
974 a[5] = a6;
975
976 final T[] b = MathArrays.buildArray(b1.getField(), 6);
977 b[0] = b1;
978 b[1] = b2;
979 b[2] = b3;
980 b[3] = b4;
981 b[4] = b5;
982 b[5] = b6;
983
984 return a1.linearCombination(a, b);
985
986 }
987
988
989
990
991
992
993
994
995 public static <T extends CalculusFieldElement<T>> FieldAngularCoordinates<T> createFromModifiedRodrigues(final T[][] r) {
996
997
998 final T rSquared = r[0][0].square().add(r[0][1].square()).add(r[0][2].square());
999 final T oPQ0 = rSquared.add(1).reciprocal().multiply(2);
1000 final T q0 = oPQ0.subtract(1);
1001 final T q1 = oPQ0.multiply(r[0][0]);
1002 final T q2 = oPQ0.multiply(r[0][1]);
1003 final T q3 = oPQ0.multiply(r[0][2]);
1004
1005
1006 final T oPQ02 = oPQ0.multiply(oPQ0);
1007 final T q0Dot = oPQ02.multiply(q0.linearCombination(r[0][0], r[1][0], r[0][1], r[1][1], r[0][2], r[1][2])).negate();
1008 final T q1Dot = oPQ0.multiply(r[1][0]).add(r[0][0].multiply(q0Dot));
1009 final T q2Dot = oPQ0.multiply(r[1][1]).add(r[0][1].multiply(q0Dot));
1010 final T q3Dot = oPQ0.multiply(r[1][2]).add(r[0][2].multiply(q0Dot));
1011 final T oX = q0.linearCombination(q1.negate(), q0Dot, q0, q1Dot, q3, q2Dot, q2.negate(), q3Dot).multiply(2);
1012 final T oY = q0.linearCombination(q2.negate(), q0Dot, q3.negate(), q1Dot, q0, q2Dot, q1, q3Dot).multiply(2);
1013 final T oZ = q0.linearCombination(q3.negate(), q0Dot, q2, q1Dot, q1.negate(), q2Dot, q0, q3Dot).multiply(2);
1014
1015
1016 final T q0DotDot = q0.subtract(1).negate().divide(oPQ0).multiply(q0Dot.square()).
1017 subtract(oPQ02.multiply(q0.linearCombination(r[0][0], r[2][0], r[0][1], r[2][1], r[0][2], r[2][2]))).
1018 subtract(q1Dot.square().add(q2Dot.square()).add(q3Dot.square()));
1019 final T q1DotDot = q0.linearCombination(oPQ0, r[2][0], r[1][0].add(r[1][0]), q0Dot, r[0][0], q0DotDot);
1020 final T q2DotDot = q0.linearCombination(oPQ0, r[2][1], r[1][1].add(r[1][1]), q0Dot, r[0][1], q0DotDot);
1021 final T q3DotDot = q0.linearCombination(oPQ0, r[2][2], r[1][2].add(r[1][2]), q0Dot, r[0][2], q0DotDot);
1022 final T oXDot = q0.linearCombination(q1.negate(), q0DotDot, q0, q1DotDot, q3, q2DotDot, q2.negate(), q3DotDot).multiply(2);
1023 final T oYDot = q0.linearCombination(q2.negate(), q0DotDot, q3.negate(), q1DotDot, q0, q2DotDot, q1, q3DotDot).multiply(2);
1024 final T oZDot = q0.linearCombination(q3.negate(), q0DotDot, q2, q1DotDot, q1.negate(), q2DotDot, q0, q3DotDot).multiply(2);
1025
1026 return new FieldAngularCoordinates<>(new FieldRotation<>(q0, q1, q2, q3, false),
1027 new FieldVector3D<>(oX, oY, oZ),
1028 new FieldVector3D<>(oXDot, oYDot, oZDot));
1029
1030 }
1031
1032 }