1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.adm.aem;
18
19 import java.io.IOException;
20 import java.util.Date;
21
22 import org.hipparchus.geometry.euclidean.threed.RotationOrder;
23 import org.orekit.data.DataContext;
24 import org.orekit.errors.OrekitInternalError;
25 import org.orekit.files.ccsds.definitions.TimeSystem;
26 import org.orekit.files.ccsds.definitions.Units;
27 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
28 import org.orekit.files.ccsds.ndm.adm.AdmCommonMetadataKey;
29 import org.orekit.files.ccsds.ndm.adm.AdmHeader;
30 import org.orekit.files.ccsds.ndm.adm.AdmMetadataKey;
31 import org.orekit.files.ccsds.ndm.adm.AttitudeType;
32 import org.orekit.files.ccsds.section.Header;
33 import org.orekit.files.ccsds.section.HeaderKey;
34 import org.orekit.files.ccsds.section.KvnStructureKey;
35 import org.orekit.files.ccsds.section.MetadataKey;
36 import org.orekit.files.ccsds.section.XmlStructureKey;
37 import org.orekit.files.ccsds.utils.ContextBinding;
38 import org.orekit.files.ccsds.utils.FileFormat;
39 import org.orekit.files.ccsds.utils.generation.AbstractMessageWriter;
40 import org.orekit.files.ccsds.utils.generation.Generator;
41 import org.orekit.files.ccsds.utils.generation.XmlGenerator;
42 import org.orekit.time.AbsoluteDate;
43 import org.orekit.utils.IERSConventions;
44 import org.orekit.utils.TimeStampedAngularCoordinates;
45 import org.orekit.utils.units.Unit;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 public class AemWriter extends AbstractMessageWriter<AdmHeader, AemSegment, Aem> {
218
219
220 public static final double CCSDS_AEM_VERS = 2.0;
221
222
223 public static final int KVN_PADDING_WIDTH = 20;
224
225
226 private static final String A_TO_B = "A2B";
227
228
229 private static final String B_TO_A = "B2A";
230
231
232 private static final String FIRST = "FIRST";
233
234
235 private static final String LAST = "LAST";
236
237
238 private static final String REF_FRAME_A = "REF_FRAME_A";
239
240
241 private static final String REF_FRAME_B = "REF_FRAME_B";
242
243
244 private static final String ROTATION = "rotation";
245
246
247 private static final String ANGLE_ATTRIBUTE = "angle";
248
249
250 private static final String ANGLE_SUFFIX = "_ANGLE";
251
252
253 private static final String RATE_ATTRIBUTE = "rate";
254
255
256 private static final String RATE_SUFFIX = "_RATE";
257
258
259
260
261
262
263
264
265
266 public AemWriter(final IERSConventions conventions, final DataContext dataContext,
267 final AbsoluteDate missionReferenceDate) {
268 super(Aem.ROOT, Aem.FORMAT_VERSION_KEY, CCSDS_AEM_VERS,
269 new ContextBinding(
270 () -> conventions,
271 () -> true, () -> dataContext, () -> ParsedUnitsBehavior.STRICT_COMPLIANCE,
272 () -> missionReferenceDate, () -> TimeSystem.UTC,
273 () -> 0.0, () -> 1.0));
274 }
275
276
277 @Override
278 protected void writeSegmentContent(final Generator generator, final double formatVersion,
279 final AemSegment segment)
280 throws IOException {
281
282 final AemMetadata metadata = segment.getMetadata();
283 writeMetadata(generator, formatVersion, metadata);
284
285
286 startAttitudeBlock(generator);
287 generator.writeComments(((AemSegment) segment).getData().getComments());
288 for (final TimeStampedAngularCoordinates coordinates : segment.getAngularCoordinates()) {
289 writeAttitudeEphemerisLine(generator, formatVersion, metadata, coordinates);
290 }
291 endAttitudeBlock(generator);
292
293 }
294
295
296
297
298
299
300
301 void writeMetadata(final Generator generator, final double formatVersion, final AemMetadata metadata)
302 throws IOException {
303
304 final ContextBinding oldContext = getContext();
305 setContext(new ContextBinding(oldContext::getConventions,
306 oldContext::isSimpleEOP,
307 oldContext::getDataContext,
308 oldContext::getParsedUnitsBehavior,
309 oldContext::getReferenceDate,
310 metadata::getTimeSystem,
311 oldContext::getClockCount,
312 oldContext::getClockRate));
313
314
315 generator.enterSection(generator.getFormat() == FileFormat.KVN ?
316 KvnStructureKey.META.name() :
317 XmlStructureKey.metadata.name());
318
319 generator.writeComments(metadata.getComments());
320
321
322 generator.writeEntry(AdmMetadataKey.OBJECT_NAME.name(), metadata.getObjectName(), null, true);
323 generator.writeEntry(AdmCommonMetadataKey.OBJECT_ID.name(), metadata.getObjectID(), null, true);
324 if (metadata.getCenter() != null) {
325 generator.writeEntry(AdmMetadataKey.CENTER_NAME.name(), metadata.getCenter().getName(), null, false);
326 }
327
328
329 generator.writeEntry(AemMetadataKey.REF_FRAME_A.name(), metadata.getEndpoints().getFrameA().getName(), null, true);
330 generator.writeEntry(AemMetadataKey.REF_FRAME_B.name(), metadata.getEndpoints().getFrameB().getName(), null, true);
331 if (formatVersion < 2.0) {
332 generator.writeEntry(AemMetadataKey.ATTITUDE_DIR.name(), metadata.getEndpoints().isA2b() ? A_TO_B : B_TO_A, null, true);
333 }
334
335
336 generator.writeEntry(MetadataKey.TIME_SYSTEM.name(), metadata.getTimeSystem(), true);
337 generator.writeEntry(AemMetadataKey.START_TIME.name(), getTimeConverter(), metadata.getStartTime(), false, true);
338 if (metadata.getUseableStartTime() != null) {
339 generator.writeEntry(AemMetadataKey.USEABLE_START_TIME.name(), getTimeConverter(), metadata.getUseableStartTime(), false, false);
340 }
341 if (metadata.getUseableStopTime() != null) {
342 generator.writeEntry(AemMetadataKey.USEABLE_STOP_TIME.name(), getTimeConverter(), metadata.getUseableStopTime(), false, false);
343 }
344 generator.writeEntry(AemMetadataKey.STOP_TIME.name(), getTimeConverter(), metadata.getStopTime(), false, true);
345
346
347 final AttitudeType attitudeType = metadata.getAttitudeType();
348 generator.writeEntry(AemMetadataKey.ATTITUDE_TYPE.name(), attitudeType.getName(formatVersion), null, true);
349 if (formatVersion < 2.0) {
350 if (attitudeType == AttitudeType.QUATERNION ||
351 attitudeType == AttitudeType.QUATERNION_DERIVATIVE ||
352 attitudeType == AttitudeType.QUATERNION_ANGVEL) {
353 generator.writeEntry(AemMetadataKey.QUATERNION_TYPE.name(), metadata.isFirst() ? FIRST : LAST, null, false);
354 }
355 }
356
357 if (attitudeType == AttitudeType.QUATERNION_EULER_RATES ||
358 attitudeType == AttitudeType.EULER_ANGLE ||
359 attitudeType == AttitudeType.EULER_ANGLE_DERIVATIVE ||
360 attitudeType == AttitudeType.EULER_ANGLE_ANGVEL) {
361 if (formatVersion < 2.0) {
362 generator.writeEntry(AemMetadataKey.EULER_ROT_SEQ.name(),
363 metadata.getEulerRotSeq().name().replace('X', '1').replace('Y', '2').replace('Z', '3'),
364 null, false);
365 } else {
366 generator.writeEntry(AemMetadataKey.EULER_ROT_SEQ.name(),
367 metadata.getEulerRotSeq().name(),
368 null, false);
369 }
370 }
371
372 if (formatVersion < 2 && attitudeType == AttitudeType.EULER_ANGLE_DERIVATIVE) {
373 generator.writeEntry(AemMetadataKey.RATE_FRAME.name(),
374 metadata.rateFrameIsA() ? REF_FRAME_A : REF_FRAME_B,
375 null, false);
376 }
377
378 if (attitudeType == AttitudeType.QUATERNION_ANGVEL ||
379 attitudeType == AttitudeType.EULER_ANGLE_ANGVEL) {
380 generator.writeEntry(AemMetadataKey.ANGVEL_FRAME.name(),
381 metadata.getFrameAngvelFrame().getName(),
382 null, true);
383 }
384
385
386 if (metadata.getInterpolationMethod() != null) {
387 generator.writeEntry(AemMetadataKey.INTERPOLATION_METHOD.name(),
388 metadata.getInterpolationMethod(),
389 null, true);
390 generator.writeEntry(AemMetadataKey.INTERPOLATION_DEGREE.name(),
391 Integer.toString(metadata.getInterpolationDegree()),
392 null, true);
393 }
394
395
396 generator.exitSection();
397
398 }
399
400
401
402
403
404
405
406
407
408 void writeAttitudeEphemerisLine(final Generator generator, final double formatVersion,
409 final AemMetadata metadata,
410 final TimeStampedAngularCoordinates attitude)
411 throws IOException {
412
413
414 final String[] data = metadata.getAttitudeType().createDataFields(metadata.isFirst(),
415 metadata.getEndpoints().isExternal2SpacecraftBody(),
416 metadata.getEulerRotSeq(),
417 metadata.isSpacecraftBodyRate(),
418 attitude);
419
420 if (generator.getFormat() == FileFormat.KVN) {
421
422
423 generator.writeRawData(generator.dateToString(getTimeConverter(), attitude.getDate()));
424
425
426 for (int index = 0; index < data.length; index++) {
427 generator.writeRawData(' ');
428 generator.writeRawData(data[index]);
429 }
430
431
432 generator.newLine();
433
434 } else {
435 final XmlGenerator xmlGenerator = (XmlGenerator) generator;
436 xmlGenerator.enterSection(XmlSubStructureKey.attitudeState.name());
437 switch (metadata.getAttitudeType()) {
438 case QUATERNION :
439 writeQuaternion(xmlGenerator, formatVersion, metadata.isFirst(), attitude.getDate(), data);
440 break;
441 case QUATERNION_DERIVATIVE :
442 writeQuaternionDerivative(xmlGenerator, formatVersion, metadata.isFirst(), attitude.getDate(), data);
443 break;
444 case QUATERNION_EULER_RATES :
445 writeQuaternionEulerRates(xmlGenerator, metadata.isFirst(), metadata.getEulerRotSeq(), attitude.getDate(), data);
446 break;
447 case QUATERNION_ANGVEL :
448 writeQuaternionAngularVelocity(xmlGenerator, attitude.getDate(), data);
449 break;
450 case EULER_ANGLE :
451 writeEulerAngle(xmlGenerator, formatVersion, metadata.getEulerRotSeq(), attitude.getDate(), data);
452 break;
453 case EULER_ANGLE_DERIVATIVE :
454 writeEulerAngleDerivative(xmlGenerator, formatVersion, metadata.getEulerRotSeq(), attitude.getDate(), data);
455 break;
456 case EULER_ANGLE_ANGVEL :
457 writeEulerAngleAngularVelocity(xmlGenerator, formatVersion, metadata.getEulerRotSeq(), attitude.getDate(), data);
458 break;
459 case SPIN :
460 writeSpin(xmlGenerator, attitude.getDate(), data);
461 break;
462 case SPIN_NUTATION :
463 writeSpinNutation(xmlGenerator, attitude.getDate(), data);
464 break;
465 case SPIN_NUTATION_MOMENTUM :
466 writeSpinNutationMomentum(xmlGenerator, attitude.getDate(), data);
467 break;
468 default :
469
470 throw new OrekitInternalError(null);
471 }
472 generator.exitSection();
473 }
474
475 }
476
477
478
479
480
481
482
483
484
485 void writeQuaternion(final XmlGenerator xmlGenerator, final double formatVersion,
486 final boolean first, final AbsoluteDate epoch, final String[] data)
487 throws IOException {
488
489 xmlGenerator.enterSection(formatVersion < 2.0 ?
490 AttitudeEntryKey.quaternionState.name() :
491 AttitudeEntryKey.quaternionEphemeris.name());
492
493
494 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
495
496
497 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
498
499
500 int i = 0;
501 if (formatVersion < 2.0 && first) {
502 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, false);
503 }
504 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, false);
505 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, false);
506 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, false);
507 if (!(formatVersion < 2.0 && first)) {
508 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, false);
509 }
510
511 xmlGenerator.exitSection();
512 xmlGenerator.exitSection();
513
514 }
515
516
517
518
519
520
521
522
523
524 void writeQuaternionDerivative(final XmlGenerator xmlGenerator, final double formatVersion,
525 final boolean first, final AbsoluteDate epoch, final String[] data)
526 throws IOException {
527
528
529 xmlGenerator.enterSection(AttitudeEntryKey.quaternionDerivative.name());
530
531
532 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
533 int i = 0;
534
535
536 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
537 if (formatVersion < 2.0 && first) {
538 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
539 }
540 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, true);
541 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, true);
542 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, true);
543 if (!(formatVersion < 2.0 && first)) {
544 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
545 }
546 xmlGenerator.exitSection();
547
548
549 xmlGenerator.enterSection(formatVersion < 2.0 ?
550 AttitudeEntryKey.quaternionRate.name() :
551 AttitudeEntryKey.quaternionDot.name());
552 if (formatVersion < 2.0 && first) {
553 xmlGenerator.writeEntry(AttitudeEntryKey.QC_DOT.name(), data[i++], Units.ONE_PER_S, true);
554 }
555 xmlGenerator.writeEntry(AttitudeEntryKey.Q1_DOT.name(), data[i++], Units.ONE_PER_S, true);
556 xmlGenerator.writeEntry(AttitudeEntryKey.Q2_DOT.name(), data[i++], Units.ONE_PER_S, true);
557 xmlGenerator.writeEntry(AttitudeEntryKey.Q3_DOT.name(), data[i++], Units.ONE_PER_S, true);
558 if (!(formatVersion < 2.0 && first)) {
559 xmlGenerator.writeEntry(AttitudeEntryKey.QC_DOT.name(), data[i++], Units.ONE_PER_S, true);
560 }
561 xmlGenerator.exitSection();
562
563 xmlGenerator.exitSection();
564
565 }
566
567
568
569
570
571
572
573
574
575 void writeQuaternionEulerRates(final XmlGenerator xmlGenerator, final boolean first, final RotationOrder order,
576 final AbsoluteDate epoch, final String[] data)
577 throws IOException {
578
579
580 xmlGenerator.enterSection(AttitudeEntryKey.quaternionEulerRate.name());
581
582
583 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
584 int i = 0;
585
586
587 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
588 if (first) {
589 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
590 }
591 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, true);
592 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, true);
593 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, true);
594 if (!first) {
595 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
596 }
597 xmlGenerator.exitSection();
598
599
600 xmlGenerator.enterSection(AttitudeEntryKey.rotationRates.name());
601 writeLabeledEulerRate(xmlGenerator, 0, order.name(), data[i++]);
602 writeLabeledEulerRate(xmlGenerator, 1, order.name(), data[i++]);
603 writeLabeledEulerRate(xmlGenerator, 2, order.name(), data[i++]);
604 xmlGenerator.exitSection();
605
606 xmlGenerator.exitSection();
607
608 }
609
610
611
612
613
614
615
616 void writeQuaternionAngularVelocity(final XmlGenerator xmlGenerator,
617 final AbsoluteDate epoch, final String[] data)
618 throws IOException {
619
620
621 xmlGenerator.enterSection(AttitudeEntryKey.quaternionAngVel.name());
622
623
624 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
625 int i = 0;
626
627
628 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
629 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, true);
630 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, true);
631 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, true);
632 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
633 xmlGenerator.exitSection();
634
635
636 xmlGenerator.enterSection(AttitudeEntryKey.angVel.name());
637 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_X.name(), data[i++], Units.DEG_PER_S, true);
638 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Y.name(), data[i++], Units.DEG_PER_S, true);
639 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Z.name(), data[i++], Units.DEG_PER_S, true);
640 xmlGenerator.exitSection();
641
642 xmlGenerator.exitSection();
643
644 }
645
646
647
648
649
650
651
652
653
654 void writeEulerAngle(final XmlGenerator xmlGenerator, final double formatVersion,
655 final RotationOrder order, final AbsoluteDate epoch, final String[] data)
656 throws IOException {
657
658
659 xmlGenerator.enterSection(AttitudeEntryKey.eulerAngle.name());
660
661
662 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
663 int i = 0;
664
665
666 if (formatVersion < 2.0) {
667 xmlGenerator.enterSection(AttitudeEntryKey.rotationAngles.name());
668 writeLabeledEulerAngle(xmlGenerator, 0, order.name(), data[i++]);
669 writeLabeledEulerAngle(xmlGenerator, 1, order.name(), data[i++]);
670 writeLabeledEulerAngle(xmlGenerator, 2, order.name(), data[i++]);
671 xmlGenerator.exitSection();
672 } else {
673 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1.name(), data[i++], Unit.DEGREE, true);
674 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2.name(), data[i++], Unit.DEGREE, true);
675 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3.name(), data[i++], Unit.DEGREE, true);
676 }
677
678 xmlGenerator.exitSection();
679
680 }
681
682
683
684
685
686
687
688
689
690 void writeEulerAngleDerivative(final XmlGenerator xmlGenerator, final double formatVersion,
691 final RotationOrder order, final AbsoluteDate epoch, final String[] data)
692 throws IOException {
693
694
695 xmlGenerator.enterSection(formatVersion < 2.0 ?
696 AttitudeEntryKey.eulerAngleRate.name() :
697 AttitudeEntryKey.eulerAngleDerivative.name());
698
699
700 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
701 int i = 0;
702
703
704 if (formatVersion < 2.0) {
705 xmlGenerator.enterSection(AttitudeEntryKey.rotationAngles.name());
706 writeLabeledEulerAngle(xmlGenerator, 0, order.name(), data[i++]);
707 writeLabeledEulerAngle(xmlGenerator, 1, order.name(), data[i++]);
708 writeLabeledEulerAngle(xmlGenerator, 2, order.name(), data[i++]);
709 xmlGenerator.exitSection();
710 xmlGenerator.enterSection(AttitudeEntryKey.rotationRates.name());
711 writeLabeledEulerRate(xmlGenerator, 0, order.name(), data[i++]);
712 writeLabeledEulerRate(xmlGenerator, 1, order.name(), data[i++]);
713 writeLabeledEulerRate(xmlGenerator, 2, order.name(), data[i++]);
714 xmlGenerator.exitSection();
715 } else {
716 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1.name(), data[i++], Unit.DEGREE, true);
717 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2.name(), data[i++], Unit.DEGREE, true);
718 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3.name(), data[i++], Unit.DEGREE, true);
719 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1_DOT.name(), data[i++], Units.DEG_PER_S, true);
720 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2_DOT.name(), data[i++], Units.DEG_PER_S, true);
721 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3_DOT.name(), data[i++], Units.DEG_PER_S, true);
722 }
723
724 xmlGenerator.exitSection();
725
726 }
727
728
729
730
731
732
733
734
735
736 void writeEulerAngleAngularVelocity(final XmlGenerator xmlGenerator, final double formatVersion, final RotationOrder order,
737 final AbsoluteDate epoch, final String[] data)
738 throws IOException {
739
740
741 xmlGenerator.enterSection(AttitudeEntryKey.eulerAngleAngVel.name());
742
743
744 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
745 int i = 0;
746
747
748 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1.name(), data[i++], Unit.DEGREE, true);
749 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2.name(), data[i++], Unit.DEGREE, true);
750 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3.name(), data[i++], Unit.DEGREE, true);
751
752
753 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_X.name(), data[i++], Units.DEG_PER_S, true);
754 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Y.name(), data[i++], Units.DEG_PER_S, true);
755 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Z.name(), data[i++], Units.DEG_PER_S, true);
756
757 xmlGenerator.exitSection();
758
759 }
760
761
762
763
764
765
766
767 void writeSpin(final XmlGenerator xmlGenerator, final AbsoluteDate epoch, final String[] data)
768 throws IOException {
769
770
771 xmlGenerator.enterSection(AttitudeEntryKey.spin.name());
772
773
774 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
775 int i = 0;
776 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ALPHA.name(), data[i++], Unit.DEGREE, true);
777 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_DELTA.name(), data[i++], Unit.DEGREE, true);
778 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE.name(), data[i++], Unit.DEGREE, true);
779 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE_VEL.name(), data[i++], Units.DEG_PER_S, true);
780
781 xmlGenerator.exitSection();
782
783 }
784
785
786
787
788
789
790
791 void writeSpinNutation(final XmlGenerator xmlGenerator, final AbsoluteDate epoch, final String[] data)
792 throws IOException {
793
794
795 xmlGenerator.enterSection(AttitudeEntryKey.spinNutation.name());
796
797
798 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
799 int i = 0;
800 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ALPHA.name(), data[i++], Unit.DEGREE, true);
801 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_DELTA.name(), data[i++], Unit.DEGREE, true);
802 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE.name(), data[i++], Unit.DEGREE, true);
803 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE_VEL.name(), data[i++], Units.DEG_PER_S, true);
804 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION.name(), data[i++], Unit.DEGREE, true);
805 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION_PER.name(), data[i++], Unit.SECOND, true);
806 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION_PHASE.name(), data[i++], Unit.DEGREE, true);
807
808 xmlGenerator.exitSection();
809
810 }
811
812
813
814
815
816
817
818 void writeSpinNutationMomentum(final XmlGenerator xmlGenerator, final AbsoluteDate epoch, final String[] data)
819 throws IOException {
820
821
822 xmlGenerator.enterSection(AttitudeEntryKey.spinNutationMom.name());
823
824
825 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
826 int i = 0;
827 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ALPHA.name(), data[i++], Unit.DEGREE, true);
828 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_DELTA.name(), data[i++], Unit.DEGREE, true);
829 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE.name(), data[i++], Unit.DEGREE, true);
830 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE_VEL.name(), data[i++], Units.DEG_PER_S, true);
831 xmlGenerator.writeEntry(AttitudeEntryKey.MOMENTUM_ALPHA.name(), data[i++], Unit.DEGREE, true);
832 xmlGenerator.writeEntry(AttitudeEntryKey.MOMENTUM_DELTA.name(), data[i++], Unit.DEGREE, true);
833 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION_VEL.name(), data[i++], Units.DEG_PER_S, true);
834
835 xmlGenerator.exitSection();
836
837 }
838
839
840
841
842
843
844
845
846 private void writeLabeledEulerAngle(final XmlGenerator xmlGenerator, final int index,
847 final String seq, final String angle)
848 throws IOException {
849 if (xmlGenerator.writeUnits(Unit.DEGREE)) {
850 xmlGenerator.writeTwoAttributesElement(ROTATION + (index + 1), angle,
851 ANGLE_ATTRIBUTE, seq.charAt(index) + ANGLE_SUFFIX,
852 XmlGenerator.UNITS,
853 xmlGenerator.siToCcsdsName(Unit.DEGREE.getName()));
854 } else {
855 xmlGenerator.writeOneAttributeElement(ROTATION + (index + 1), angle,
856 ANGLE_ATTRIBUTE, seq.charAt(index) + ANGLE_SUFFIX);
857 }
858 }
859
860
861
862
863
864
865
866
867 private void writeLabeledEulerRate(final XmlGenerator xmlGenerator, final int index, final String seq, final String rate)
868 throws IOException {
869 if (xmlGenerator.writeUnits(Units.DEG_PER_S)) {
870 xmlGenerator.writeTwoAttributesElement(ROTATION + (index + 1), rate,
871 RATE_ATTRIBUTE, seq.charAt(index) + RATE_SUFFIX,
872 XmlGenerator.UNITS,
873 xmlGenerator.siToCcsdsName(Units.DEG_PER_S.getName()));
874 } else {
875 xmlGenerator.writeOneAttributeElement(ROTATION + (index + 1), rate,
876 RATE_ATTRIBUTE, seq.charAt(index) + RATE_SUFFIX);
877 }
878 }
879
880
881
882
883
884 void startAttitudeBlock(final Generator generator) throws IOException {
885 generator.enterSection(generator.getFormat() == FileFormat.KVN ?
886 KvnStructureKey.DATA.name() :
887 XmlStructureKey.data.name());
888 }
889
890
891
892
893
894 void endAttitudeBlock(final Generator generator) throws IOException {
895 generator.exitSection();
896 }
897
898 }