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