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 generator.getFormatter());
420
421 if (generator.getFormat() == FileFormat.KVN) {
422
423
424 generator.writeRawData(generator.dateToString(getTimeConverter(), attitude.getDate()));
425
426
427 for (String datum : data) {
428 generator.writeRawData(' ');
429 generator.writeRawData(datum);
430 }
431
432
433 generator.newLine();
434
435 } else {
436 final XmlGenerator xmlGenerator = (XmlGenerator) generator;
437 xmlGenerator.enterSection(XmlSubStructureKey.attitudeState.name());
438 switch (metadata.getAttitudeType()) {
439 case QUATERNION :
440 writeQuaternion(xmlGenerator, formatVersion, metadata.isFirst(), attitude.getDate(), data);
441 break;
442 case QUATERNION_DERIVATIVE :
443 writeQuaternionDerivative(xmlGenerator, formatVersion, metadata.isFirst(), attitude.getDate(), data);
444 break;
445 case QUATERNION_EULER_RATES :
446 writeQuaternionEulerRates(xmlGenerator, metadata.isFirst(), metadata.getEulerRotSeq(), attitude.getDate(), data);
447 break;
448 case QUATERNION_ANGVEL :
449 writeQuaternionAngularVelocity(xmlGenerator, attitude.getDate(), data);
450 break;
451 case EULER_ANGLE :
452 writeEulerAngle(xmlGenerator, formatVersion, metadata.getEulerRotSeq(), attitude.getDate(), data);
453 break;
454 case EULER_ANGLE_DERIVATIVE :
455 writeEulerAngleDerivative(xmlGenerator, formatVersion, metadata.getEulerRotSeq(), attitude.getDate(), data);
456 break;
457 case EULER_ANGLE_ANGVEL :
458 writeEulerAngleAngularVelocity(xmlGenerator, formatVersion, metadata.getEulerRotSeq(), attitude.getDate(), data);
459 break;
460 case SPIN :
461 writeSpin(xmlGenerator, attitude.getDate(), data);
462 break;
463 case SPIN_NUTATION :
464 writeSpinNutation(xmlGenerator, attitude.getDate(), data);
465 break;
466 case SPIN_NUTATION_MOMENTUM :
467 writeSpinNutationMomentum(xmlGenerator, attitude.getDate(), data);
468 break;
469 default :
470
471 throw new OrekitInternalError(null);
472 }
473 generator.exitSection();
474 }
475
476 }
477
478
479
480
481
482
483
484
485
486 void writeQuaternion(final XmlGenerator xmlGenerator, final double formatVersion,
487 final boolean first, final AbsoluteDate epoch, final String[] data)
488 throws IOException {
489
490 xmlGenerator.enterSection(formatVersion < 2.0 ?
491 AttitudeEntryKey.quaternionState.name() :
492 AttitudeEntryKey.quaternionEphemeris.name());
493
494
495 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
496
497
498 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
499
500
501 int i = 0;
502 if (formatVersion < 2.0 && first) {
503 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, false);
504 }
505 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, false);
506 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, false);
507 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, false);
508 if (!(formatVersion < 2.0 && first)) {
509 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, false);
510 }
511
512 xmlGenerator.exitSection();
513 xmlGenerator.exitSection();
514
515 }
516
517
518
519
520
521
522
523
524
525 void writeQuaternionDerivative(final XmlGenerator xmlGenerator, final double formatVersion,
526 final boolean first, final AbsoluteDate epoch, final String[] data)
527 throws IOException {
528
529
530 xmlGenerator.enterSection(AttitudeEntryKey.quaternionDerivative.name());
531
532
533 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
534 int i = 0;
535
536
537 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
538 if (formatVersion < 2.0 && first) {
539 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
540 }
541 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, true);
542 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, true);
543 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, true);
544 if (!(formatVersion < 2.0 && first)) {
545 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
546 }
547 xmlGenerator.exitSection();
548
549
550 xmlGenerator.enterSection(formatVersion < 2.0 ?
551 AttitudeEntryKey.quaternionRate.name() :
552 AttitudeEntryKey.quaternionDot.name());
553 if (formatVersion < 2.0 && first) {
554 xmlGenerator.writeEntry(AttitudeEntryKey.QC_DOT.name(), data[i++], Units.ONE_PER_S, true);
555 }
556 xmlGenerator.writeEntry(AttitudeEntryKey.Q1_DOT.name(), data[i++], Units.ONE_PER_S, true);
557 xmlGenerator.writeEntry(AttitudeEntryKey.Q2_DOT.name(), data[i++], Units.ONE_PER_S, true);
558 xmlGenerator.writeEntry(AttitudeEntryKey.Q3_DOT.name(), data[i++], Units.ONE_PER_S, true);
559 if (!(formatVersion < 2.0 && first)) {
560 xmlGenerator.writeEntry(AttitudeEntryKey.QC_DOT.name(), data[i++], Units.ONE_PER_S, true);
561 }
562 xmlGenerator.exitSection();
563
564 xmlGenerator.exitSection();
565
566 }
567
568
569
570
571
572
573
574
575
576 void writeQuaternionEulerRates(final XmlGenerator xmlGenerator, final boolean first, final RotationOrder order,
577 final AbsoluteDate epoch, final String[] data)
578 throws IOException {
579
580
581 xmlGenerator.enterSection(AttitudeEntryKey.quaternionEulerRate.name());
582
583
584 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
585 int i = 0;
586
587
588 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
589 if (first) {
590 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
591 }
592 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, true);
593 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, true);
594 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, true);
595 if (!first) {
596 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
597 }
598 xmlGenerator.exitSection();
599
600
601 xmlGenerator.enterSection(AttitudeEntryKey.rotationRates.name());
602 writeLabeledEulerRate(xmlGenerator, 0, order.name(), data[i++]);
603 writeLabeledEulerRate(xmlGenerator, 1, order.name(), data[i++]);
604 writeLabeledEulerRate(xmlGenerator, 2, order.name(), data[i++]);
605 xmlGenerator.exitSection();
606
607 xmlGenerator.exitSection();
608
609 }
610
611
612
613
614
615
616
617 void writeQuaternionAngularVelocity(final XmlGenerator xmlGenerator,
618 final AbsoluteDate epoch, final String[] data)
619 throws IOException {
620
621
622 xmlGenerator.enterSection(AttitudeEntryKey.quaternionAngVel.name());
623
624
625 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
626 int i = 0;
627
628
629 xmlGenerator.enterSection(AttitudeEntryKey.quaternion.name());
630 xmlGenerator.writeEntry(AttitudeEntryKey.Q1.name(), data[i++], Unit.ONE, true);
631 xmlGenerator.writeEntry(AttitudeEntryKey.Q2.name(), data[i++], Unit.ONE, true);
632 xmlGenerator.writeEntry(AttitudeEntryKey.Q3.name(), data[i++], Unit.ONE, true);
633 xmlGenerator.writeEntry(AttitudeEntryKey.QC.name(), data[i++], Unit.ONE, true);
634 xmlGenerator.exitSection();
635
636
637 xmlGenerator.enterSection(AttitudeEntryKey.angVel.name());
638 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_X.name(), data[i++], Units.DEG_PER_S, true);
639 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Y.name(), data[i++], Units.DEG_PER_S, true);
640 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Z.name(), data[i++], Units.DEG_PER_S, true);
641 xmlGenerator.exitSection();
642
643 xmlGenerator.exitSection();
644
645 }
646
647
648
649
650
651
652
653
654
655 void writeEulerAngle(final XmlGenerator xmlGenerator, final double formatVersion,
656 final RotationOrder order, final AbsoluteDate epoch, final String[] data)
657 throws IOException {
658
659
660 xmlGenerator.enterSection(AttitudeEntryKey.eulerAngle.name());
661
662
663 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
664 int i = 0;
665
666
667 if (formatVersion < 2.0) {
668 xmlGenerator.enterSection(AttitudeEntryKey.rotationAngles.name());
669 writeLabeledEulerAngle(xmlGenerator, 0, order.name(), data[i++]);
670 writeLabeledEulerAngle(xmlGenerator, 1, order.name(), data[i++]);
671 writeLabeledEulerAngle(xmlGenerator, 2, order.name(), data[i++]);
672 xmlGenerator.exitSection();
673 } else {
674 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1.name(), data[i++], Unit.DEGREE, true);
675 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2.name(), data[i++], Unit.DEGREE, true);
676 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3.name(), data[i++], Unit.DEGREE, true);
677 }
678
679 xmlGenerator.exitSection();
680
681 }
682
683
684
685
686
687
688
689
690
691 void writeEulerAngleDerivative(final XmlGenerator xmlGenerator, final double formatVersion,
692 final RotationOrder order, final AbsoluteDate epoch, final String[] data)
693 throws IOException {
694
695
696 xmlGenerator.enterSection(formatVersion < 2.0 ?
697 AttitudeEntryKey.eulerAngleRate.name() :
698 AttitudeEntryKey.eulerAngleDerivative.name());
699
700
701 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
702 int i = 0;
703
704
705 if (formatVersion < 2.0) {
706 xmlGenerator.enterSection(AttitudeEntryKey.rotationAngles.name());
707 writeLabeledEulerAngle(xmlGenerator, 0, order.name(), data[i++]);
708 writeLabeledEulerAngle(xmlGenerator, 1, order.name(), data[i++]);
709 writeLabeledEulerAngle(xmlGenerator, 2, order.name(), data[i++]);
710 xmlGenerator.exitSection();
711 xmlGenerator.enterSection(AttitudeEntryKey.rotationRates.name());
712 writeLabeledEulerRate(xmlGenerator, 0, order.name(), data[i++]);
713 writeLabeledEulerRate(xmlGenerator, 1, order.name(), data[i++]);
714 writeLabeledEulerRate(xmlGenerator, 2, order.name(), data[i++]);
715 xmlGenerator.exitSection();
716 } else {
717 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1.name(), data[i++], Unit.DEGREE, true);
718 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2.name(), data[i++], Unit.DEGREE, true);
719 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3.name(), data[i++], Unit.DEGREE, true);
720 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1_DOT.name(), data[i++], Units.DEG_PER_S, true);
721 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2_DOT.name(), data[i++], Units.DEG_PER_S, true);
722 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3_DOT.name(), data[i++], Units.DEG_PER_S, true);
723 }
724
725 xmlGenerator.exitSection();
726
727 }
728
729
730
731
732
733
734
735
736
737 void writeEulerAngleAngularVelocity(final XmlGenerator xmlGenerator, final double formatVersion, final RotationOrder order,
738 final AbsoluteDate epoch, final String[] data)
739 throws IOException {
740
741
742 xmlGenerator.enterSection(AttitudeEntryKey.eulerAngleAngVel.name());
743
744
745 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
746 int i = 0;
747
748
749 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_1.name(), data[i++], Unit.DEGREE, true);
750 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_2.name(), data[i++], Unit.DEGREE, true);
751 xmlGenerator.writeEntry(AttitudeEntryKey.ANGLE_3.name(), data[i++], Unit.DEGREE, true);
752
753
754 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_X.name(), data[i++], Units.DEG_PER_S, true);
755 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Y.name(), data[i++], Units.DEG_PER_S, true);
756 xmlGenerator.writeEntry(AttitudeEntryKey.ANGVEL_Z.name(), data[i++], Units.DEG_PER_S, true);
757
758 xmlGenerator.exitSection();
759
760 }
761
762
763
764
765
766
767
768 void writeSpin(final XmlGenerator xmlGenerator, final AbsoluteDate epoch, final String[] data)
769 throws IOException {
770
771
772 xmlGenerator.enterSection(AttitudeEntryKey.spin.name());
773
774
775 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
776 int i = 0;
777 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ALPHA.name(), data[i++], Unit.DEGREE, true);
778 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_DELTA.name(), data[i++], Unit.DEGREE, true);
779 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE.name(), data[i++], Unit.DEGREE, true);
780 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE_VEL.name(), data[i++], Units.DEG_PER_S, true);
781
782 xmlGenerator.exitSection();
783
784 }
785
786
787
788
789
790
791
792 void writeSpinNutation(final XmlGenerator xmlGenerator, final AbsoluteDate epoch, final String[] data)
793 throws IOException {
794
795
796 xmlGenerator.enterSection(AttitudeEntryKey.spinNutation.name());
797
798
799 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
800 int i = 0;
801 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ALPHA.name(), data[i++], Unit.DEGREE, true);
802 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_DELTA.name(), data[i++], Unit.DEGREE, true);
803 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE.name(), data[i++], Unit.DEGREE, true);
804 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE_VEL.name(), data[i++], Units.DEG_PER_S, true);
805 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION.name(), data[i++], Unit.DEGREE, true);
806 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION_PER.name(), data[i++], Unit.SECOND, true);
807 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION_PHASE.name(), data[i++], Unit.DEGREE, true);
808
809 xmlGenerator.exitSection();
810
811 }
812
813
814
815
816
817
818
819 void writeSpinNutationMomentum(final XmlGenerator xmlGenerator, final AbsoluteDate epoch, final String[] data)
820 throws IOException {
821
822
823 xmlGenerator.enterSection(AttitudeEntryKey.spinNutationMom.name());
824
825
826 xmlGenerator.writeEntry(AttitudeEntryKey.EPOCH.name(), getTimeConverter(), epoch, false, true);
827 int i = 0;
828 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ALPHA.name(), data[i++], Unit.DEGREE, true);
829 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_DELTA.name(), data[i++], Unit.DEGREE, true);
830 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE.name(), data[i++], Unit.DEGREE, true);
831 xmlGenerator.writeEntry(AttitudeEntryKey.SPIN_ANGLE_VEL.name(), data[i++], Units.DEG_PER_S, true);
832 xmlGenerator.writeEntry(AttitudeEntryKey.MOMENTUM_ALPHA.name(), data[i++], Unit.DEGREE, true);
833 xmlGenerator.writeEntry(AttitudeEntryKey.MOMENTUM_DELTA.name(), data[i++], Unit.DEGREE, true);
834 xmlGenerator.writeEntry(AttitudeEntryKey.NUTATION_VEL.name(), data[i++], Units.DEG_PER_S, true);
835
836 xmlGenerator.exitSection();
837
838 }
839
840
841
842
843
844
845
846
847 private void writeLabeledEulerAngle(final XmlGenerator xmlGenerator, final int index,
848 final String seq, final String angle)
849 throws IOException {
850 if (xmlGenerator.writeUnits(Unit.DEGREE)) {
851 xmlGenerator.writeTwoAttributesElement(ROTATION + (index + 1), angle,
852 ANGLE_ATTRIBUTE, seq.charAt(index) + ANGLE_SUFFIX,
853 XmlGenerator.UNITS,
854 xmlGenerator.siToCcsdsName(Unit.DEGREE.getName()));
855 } else {
856 xmlGenerator.writeOneAttributeElement(ROTATION + (index + 1), angle,
857 ANGLE_ATTRIBUTE, seq.charAt(index) + ANGLE_SUFFIX);
858 }
859 }
860
861
862
863
864
865
866
867
868 private void writeLabeledEulerRate(final XmlGenerator xmlGenerator, final int index, final String seq, final String rate)
869 throws IOException {
870 if (xmlGenerator.writeUnits(Units.DEG_PER_S)) {
871 xmlGenerator.writeTwoAttributesElement(ROTATION + (index + 1), rate,
872 RATE_ATTRIBUTE, seq.charAt(index) + RATE_SUFFIX,
873 XmlGenerator.UNITS,
874 xmlGenerator.siToCcsdsName(Units.DEG_PER_S.getName()));
875 } else {
876 xmlGenerator.writeOneAttributeElement(ROTATION + (index + 1), rate,
877 RATE_ATTRIBUTE, seq.charAt(index) + RATE_SUFFIX);
878 }
879 }
880
881
882
883
884
885 void startAttitudeBlock(final Generator generator) throws IOException {
886 generator.enterSection(generator.getFormat() == FileFormat.KVN ?
887 KvnStructureKey.DATA.name() :
888 XmlStructureKey.data.name());
889 }
890
891
892
893
894
895 void endAttitudeBlock(final Generator generator) throws IOException {
896 generator.exitSection();
897 }
898
899 }