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