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