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