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