ApmWriter.java

  1. /* Copyright 2002-2024 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.files.ccsds.ndm.adm.apm;

  18. import java.io.IOException;

  19. import org.orekit.data.DataContext;
  20. import org.orekit.files.ccsds.definitions.TimeSystem;
  21. import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
  22. import org.orekit.files.ccsds.ndm.adm.AdmCommonMetadataWriter;
  23. import org.orekit.files.ccsds.ndm.adm.AdmHeader;
  24. import org.orekit.files.ccsds.ndm.adm.AdmMetadata;
  25. import org.orekit.files.ccsds.section.Segment;
  26. import org.orekit.files.ccsds.section.XmlStructureKey;
  27. import org.orekit.files.ccsds.utils.ContextBinding;
  28. import org.orekit.files.ccsds.utils.FileFormat;
  29. import org.orekit.files.ccsds.utils.generation.AbstractMessageWriter;
  30. import org.orekit.files.ccsds.utils.generation.Generator;
  31. import org.orekit.time.AbsoluteDate;
  32. import org.orekit.utils.IERSConventions;


  33. /**
  34.  * Writer for CCSDS Orbit Parameter Message.
  35.  *
  36.  * @author Luc Maisonobe
  37.  * @since 11.0
  38.  */
  39. public class ApmWriter extends AbstractMessageWriter<AdmHeader, Segment<AdmMetadata, ApmData>, Apm> {

  40.     /** Version number implemented. **/
  41.     public static final double CCSDS_APM_VERS = 1.0;

  42.     /** Padding width for aligning the '=' sign. */
  43.     public static final int KVN_PADDING_WIDTH = 17;

  44.     /** Complete constructor.
  45.      * <p>
  46.      * Calling this constructor directly is not recommended. Users should rather use
  47.      * {@link org.orekit.files.ccsds.ndm.WriterBuilder#buildApmWriter()
  48.      * writerBuilder.buildOpmWriter()}.
  49.      * </p>
  50.      * @param conventions IERS Conventions
  51.      * @param dataContext used to retrieve frames, time scales, etc.
  52.      * @param missionReferenceDate reference date for Mission Elapsed Time or Mission Relative Time time systems
  53.      */
  54.     public ApmWriter(final IERSConventions conventions, final DataContext dataContext,
  55.                      final AbsoluteDate missionReferenceDate) {
  56.         super(Apm.ROOT, Apm.FORMAT_VERSION_KEY, CCSDS_APM_VERS,
  57.               new ContextBinding(
  58.                   () -> conventions,
  59.                   () -> false, () -> dataContext, () -> ParsedUnitsBehavior.STRICT_COMPLIANCE,
  60.                   () -> missionReferenceDate, () -> TimeSystem.UTC,
  61.                   () -> 0.0, () -> 1.0));
  62.     }

  63.     /** {@inheritDoc} */
  64.     @Override
  65.     protected void writeSegmentContent(final Generator generator, final double formatVersion,
  66.                                        final Segment<AdmMetadata, ApmData> segment)
  67.         throws IOException {

  68.         // write the metadata
  69.         final ContextBinding oldContext = getContext();
  70.         final AdmMetadata    metadata   = segment.getMetadata();
  71.         setContext(new ContextBinding(oldContext::getConventions,
  72.                                       oldContext::isSimpleEOP,
  73.                                       oldContext::getDataContext,
  74.                                       oldContext::getParsedUnitsBehavior,
  75.                                       oldContext::getReferenceDate,
  76.                                       metadata::getTimeSystem,
  77.                                       oldContext::getClockCount,
  78.                                       oldContext::getClockRate));
  79.         new AdmCommonMetadataWriter(metadata).write(generator);

  80.         // start data block
  81.         if (generator.getFormat() == FileFormat.XML) {
  82.             generator.enterSection(XmlStructureKey.data.name());
  83.         }

  84.         generator.writeComments(segment.getData().getComments());
  85.         if (formatVersion >= 2.0) {
  86.             // starting with version 2, epoch is outside of other blocks
  87.             generator.writeEntry("EPOCH", getTimeConverter(), segment.getData().getEpoch(), false, true);
  88.         }

  89.         if (segment.getData().getQuaternionBlock() != null) {
  90.             // write quaternion block
  91.             final String xmlTag = ApmDataSubStructureKey.quaternionState.name();
  92.             final String kvnTag = formatVersion < 2.0 ? null : ApmDataSubStructureKey.QUAT.name();
  93.             new ApmQuaternionWriter(formatVersion, xmlTag, kvnTag,
  94.                                     segment.getData().getQuaternionBlock(),
  95.                                     formatVersion >= 2.0 ? null : segment.getData().getEpoch(),
  96.                                                          getTimeConverter()).
  97.             write(generator);
  98.         }

  99.         if (segment.getData().getEulerBlock() != null) {
  100.             // write optional Euler block for three axis stabilized satellites
  101.             final String xmlTag = formatVersion < 2.0 ?
  102.                                   ApmDataSubStructureKey.eulerElementsThree.name() :
  103.                                   ApmDataSubStructureKey.eulerAngleState.name();
  104.             final String kvnTag = formatVersion < 2.0 ? null : ApmDataSubStructureKey.EULER.name();
  105.             new EulerWriter(formatVersion, xmlTag, kvnTag,
  106.                             segment.getData().getEulerBlock()).
  107.             write(generator);
  108.         }

  109.         if (segment.getData().getAngularVelocityBlock() != null) {
  110.             // write optional angular velocity block
  111.             final String xmlTag = ApmDataSubStructureKey.angularVelocity.name();
  112.             final String kvnTag = ApmDataSubStructureKey.ANGVEL.name();
  113.             new AngularVelocityWriter(xmlTag, kvnTag,
  114.                                       segment.getData().getAngularVelocityBlock()).
  115.             write(generator);
  116.         }

  117.         if (segment.getData().getSpinStabilizedBlock() != null) {
  118.             // write optional block for spin stabilized satellites
  119.             final String xmlTag;
  120.             final String kvnTag;
  121.             if (formatVersion < 2.0) {
  122.                 xmlTag = ApmDataSubStructureKey.eulerElementsSpin.name();
  123.                 kvnTag = null;
  124.             } else {
  125.                 xmlTag = ApmDataSubStructureKey.spin.name();
  126.                 kvnTag = ApmDataSubStructureKey.SPIN.name();
  127.             }
  128.             new SpinStabilizedWriter(formatVersion, xmlTag, kvnTag,
  129.                                      segment.getData().getSpinStabilizedBlock()).
  130.             write(generator);
  131.         }

  132.         if (segment.getData().getInertiaBlock() != null) {
  133.             // write optional spacecraft parameters block
  134.             final String xmlTag = formatVersion < 2.0 ?
  135.                                   ApmDataSubStructureKey.spacecraftParameters.name() :
  136.                                   ApmDataSubStructureKey.inertia.name();
  137.             final String kvnTag = formatVersion < 2.0 ? null : ApmDataSubStructureKey.INERTIA.name();
  138.             new InertiaWriter(formatVersion, xmlTag, kvnTag,
  139.                               segment.getData().getInertiaBlock()).
  140.             write(generator);
  141.         }

  142.         if (!segment.getData().getManeuvers().isEmpty()) {
  143.             for (final Maneuver maneuver : segment.getData().getManeuvers()) {
  144.                 // write optional maneuver block
  145.                 final String xmlTag = ApmDataSubStructureKey.maneuverParameters.name();
  146.                 final String kvnTag = formatVersion < 2.0 ? null : ApmDataSubStructureKey.MAN.name();
  147.                 new ManeuverWriter(formatVersion, xmlTag, kvnTag,
  148.                                    maneuver, getTimeConverter()).write(generator);
  149.             }
  150.         }

  151.         // stop data block
  152.         if (generator.getFormat() == FileFormat.XML) {
  153.             generator.exitSection();
  154.         }

  155.     }

  156. }