AEMWriter.java

  1. /* Copyright 2002-2020 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;

  18. import java.io.BufferedWriter;
  19. import java.io.IOException;
  20. import java.nio.charset.StandardCharsets;
  21. import java.nio.file.Files;
  22. import java.nio.file.Paths;
  23. import java.util.LinkedHashMap;
  24. import java.util.List;
  25. import java.util.Map;

  26. import org.orekit.errors.OrekitIllegalArgumentException;
  27. import org.orekit.errors.OrekitMessages;
  28. import org.orekit.files.ccsds.AEMFile.AemSatelliteEphemeris;
  29. import org.orekit.files.ccsds.AEMFile.AttitudeEphemeridesBlock;
  30. import org.orekit.files.ccsds.StreamingAemWriter.AEMSegment;
  31. import org.orekit.time.TimeScale;
  32. import org.orekit.utils.TimeStampedAngularCoordinates;

  33. /**
  34.  * A writer for Attitude Ephemeris Messsage (AEM) files.
  35.  * @author Bryan Cazabonne
  36.  * @since 10.2
  37.  */
  38. public class AEMWriter {

  39.     /** Originator name, usually the organization and/or country. **/
  40.     private final String originator;

  41.     /** Space object ID, usually an official international designator such as "1998-067A". */
  42.     private final String spaceObjectId;

  43.     /** Space object name, usually a common name for an object like "ISS". **/
  44.     private final String spaceObjectName;

  45.     /**
  46.      * Standard default constructor that creates a writer with default
  47.      * configurations.
  48.      */
  49.     public AEMWriter() {
  50.         this(StreamingAemWriter.DEFAULT_ORIGINATOR, null, null);
  51.     }

  52.     /**
  53.      * Constructor used to create a new AEM writer configured with the necessary
  54.      * parameters to successfully fill in all required fields that aren't part
  55.      * of a standard object.
  56.      *
  57.      * @param originator the originator field string
  58.      * @param spaceObjectId the spacecraft ID
  59.      * @param spaceObjectName the space object common name
  60.      */
  61.     public AEMWriter(final String originator, final String spaceObjectId,
  62.                      final String spaceObjectName) {
  63.         this.originator          = originator;
  64.         this.spaceObjectId       = spaceObjectId;
  65.         this.spaceObjectName     = spaceObjectName;
  66.     }

  67.     /**
  68.      * Write the passed in {@link AEMFile} using the passed in {@link Appendable}.
  69.      * @param writer a configured Appendable to feed with text
  70.      * @param aemFile  a populated aem file to serialize into the buffer
  71.      * @throws IOException if any buffer writing operations fail or if the underlying
  72.      *         format doesn't support a configuration in the EphemerisFile
  73.      *         for example having multiple satellites in one file, having
  74.      *         the origin at an unspecified celestial body, etc.)
  75.      */
  76.     public void write(final Appendable writer, final AEMFile aemFile)
  77.         throws IOException {

  78.         if (writer == null) {
  79.             throw new OrekitIllegalArgumentException(OrekitMessages.NULL_ARGUMENT, "writer");
  80.         }

  81.         if (aemFile == null) {
  82.             return;
  83.         }

  84.         final String idToProcess;
  85.         if (spaceObjectId != null) {
  86.             if (aemFile.getSatellites().containsKey(spaceObjectId)) {
  87.                 idToProcess = spaceObjectId;
  88.             } else {
  89.                 throw new OrekitIllegalArgumentException(OrekitMessages.VALUE_NOT_FOUND, spaceObjectId, "ephemerisFile");
  90.             }
  91.         } else if (aemFile.getSatellites().keySet().size() == 1) {
  92.             idToProcess = aemFile.getSatellites().keySet().iterator().next();
  93.         } else {
  94.             throw new OrekitIllegalArgumentException(OrekitMessages.EPHEMERIS_FILE_NO_MULTI_SUPPORT);
  95.         }

  96.         // Get satellite and attitude ephemeris segments to output.
  97.         final AemSatelliteEphemeris          satEphem = aemFile.getSatellites().get(idToProcess);
  98.         final List<AttitudeEphemeridesBlock> segments = satEphem.getSegments();
  99.         if (segments.isEmpty()) {
  100.             // No data -> No output
  101.             return;
  102.         }
  103.         // First segment
  104.         final AttitudeEphemeridesBlock firstSegment = segments.get(0);

  105.         final String objectName = this.spaceObjectName == null ? idToProcess : this.spaceObjectName;
  106.         // Only one time scale per AEM file, see Section 4.2.5.4.2
  107.         final TimeScale timeScale = firstSegment.getTimeScale();
  108.         // Metadata that is constant for the whole AEM file
  109.         final Map<Keyword, String> metadata = new LinkedHashMap<>();
  110.         metadata.put(Keyword.TIME_SYSTEM, firstSegment.getTimeScaleString());
  111.         metadata.put(Keyword.ORIGINATOR,  this.originator);
  112.         // Only one object in an AEM file, see Section 2.3.1
  113.         metadata.put(Keyword.OBJECT_NAME,   objectName);
  114.         metadata.put(Keyword.OBJECT_ID,     idToProcess);
  115.         // Writer for AEM files
  116.         final StreamingAemWriter aemWriter =
  117.                         new StreamingAemWriter(writer, timeScale, metadata);
  118.         aemWriter.writeHeader();

  119.         // Loop on segments
  120.         for (final AttitudeEphemeridesBlock segment : segments) {
  121.             // Segment specific metadata
  122.             metadata.clear();
  123.             metadata.put(Keyword.CENTER_NAME,          segment.getFrameCenterString());
  124.             metadata.put(Keyword.REF_FRAME_A,          segment.getRefFrameAString());
  125.             metadata.put(Keyword.REF_FRAME_B,          segment.getRefFrameBString());
  126.             metadata.put(Keyword.ATTITUDE_DIR,         segment.getAttitudeDirection());
  127.             metadata.put(Keyword.START_TIME,           segment.getStart().toString(timeScale));
  128.             metadata.put(Keyword.STOP_TIME,            segment.getStop().toString(timeScale));
  129.             metadata.put(Keyword.ATTITUDE_TYPE,        segment.getAttitudeType());
  130.             metadata.put(Keyword.INTERPOLATION_METHOD, segment.getInterpolationMethod());
  131.             metadata.put(Keyword.INTERPOLATION_DEGREE, String.valueOf(segment.getInterpolationDegree()));

  132.             final AEMSegment segmentWriter = aemWriter.newSegment(metadata);
  133.             segmentWriter.writeMetadata();
  134.             segmentWriter.startAttitudeBlock();
  135.             // Loop on attitude data
  136.             for (final TimeStampedAngularCoordinates coordinates : segment.getAngularCoordinates()) {
  137.                 segmentWriter.writeAttitudeEphemerisLine(coordinates, segment.isFirst(),
  138.                                                          segment.getAttitudeType(), segment.getRotationOrder());
  139.             }
  140.             segmentWriter.endAttitudeBlock();
  141.         }

  142.     }

  143.     /**
  144.      * Write the passed in {@link AEMFile} to a file at the output path specified.
  145.      * @param outputFilePath a file path that the corresponding file will be written to
  146.      * @param aemFile a populated aem file to serialize into the buffer
  147.      * @throws IOException if any file writing operations fail or if the underlying
  148.      *         format doesn't support a configuration in the EphemerisFile
  149.      *         (for example having multiple satellites in one file, having
  150.      *         the origin at an unspecified celestial body, etc.)
  151.      */
  152.     public void write(final String outputFilePath, final AEMFile aemFile)
  153.         throws IOException {
  154.         try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputFilePath), StandardCharsets.UTF_8)) {
  155.             write(writer, aemFile);
  156.         }
  157.     }

  158. }