EphemerisOemWriter.java
- /* Copyright 2016 Applied Defense Solutions (ADS)
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * ADS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.files.ccsds.ndm.odm.oem;
- import java.io.IOException;
- import java.util.List;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitIllegalArgumentException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.files.ccsds.definitions.FrameFacade;
- import org.orekit.files.ccsds.ndm.odm.OdmHeader;
- import org.orekit.files.ccsds.utils.FileFormat;
- import org.orekit.files.ccsds.utils.generation.Generator;
- import org.orekit.files.ccsds.utils.generation.KvnGenerator;
- import org.orekit.files.ccsds.utils.generation.XmlGenerator;
- import org.orekit.files.general.EphemerisFile;
- import org.orekit.files.general.EphemerisFile.SatelliteEphemeris;
- import org.orekit.files.general.EphemerisFileWriter;
- import org.orekit.utils.CartesianDerivativesFilter;
- import org.orekit.utils.TimeStampedPVCoordinates;
- /** An {@link EphemerisFileWriter} generating {@link Oem OEM} files.
- * @author Hank Grabowski
- * @author Evan Ward
- * @since 9.0
- * @see <a href="https://public.ccsds.org/Pubs/502x0b2c1.pdf">CCSDS 502.0-B-2 Orbit Data
- * Messages</a>
- * @see <a href="https://public.ccsds.org/Pubs/500x0g4.pdf">CCSDS 500.0-G-4 Navigation
- * Data Definitions and Conventions</a>
- * @see StreamingOemWriter
- */
- public class EphemerisOemWriter implements EphemerisFileWriter {
- /** Underlying writer. */
- private final OemWriter writer;
- /** Header. */
- private final OdmHeader header;
- /** Current metadata. */
- private final OemMetadata metadata;
- /** File format to use. */
- private final FileFormat fileFormat;
- /** Output name for error messages. */
- private final String outputName;
- /** Maximum offset for relative dates.
- * @since 12.0
- */
- private final double maxRelativeOffset;
- /** Column number for aligning units. */
- private final int unitsColumn;
- /**
- * Constructor used to create a new OEM writer configured with the necessary parameters
- * to successfully fill in all required fields that aren't part of a standard object.
- * <p>
- * If the mandatory header entries are not present (or if header is null),
- * built-in defaults will be used
- * </p>
- * <p>
- * The writer is built from the complete header and partial metadata. The template
- * metadata is used to initialize and independent local copy, that will be updated
- * as new segments are written (with at least the segment start and stop will change,
- * but some other parts may change too). The {@code template} argument itself is not
- * changed.
- * </p>
- * @param writer underlying writer
- * @param header file header (may be null)
- * @param template template for metadata
- * @param fileFormat file format to use
- * @param outputName output name for error messages
- * @param maxRelativeOffset maximum offset in seconds to use relative dates
- * (if a date is too far from reference, it will be displayed as calendar elements)
- * @param unitsColumn columns number for aligning units (if negative or zero, units are not output)
- * @since 12.0
- */
- public EphemerisOemWriter(final OemWriter writer,
- final OdmHeader header, final OemMetadata template,
- final FileFormat fileFormat, final String outputName,
- final double maxRelativeOffset, final int unitsColumn) {
- this.writer = writer;
- this.header = header;
- this.metadata = template.copy(header == null ? writer.getDefaultVersion() : header.getFormatVersion());
- this.fileFormat = fileFormat;
- this.outputName = outputName;
- this.maxRelativeOffset = maxRelativeOffset;
- this.unitsColumn = unitsColumn;
- }
- /** {@inheritDoc}
- * <p>
- * As {@code EphemerisFile.SatelliteEphemeris} does not have all the entries
- * from {@link OemMetadata}, the only values that will be extracted from the
- * {@code ephemerisFile} will be the start time, stop time, reference frame, interpolation
- * method and interpolation degree. The missing values (like object name, local spacecraft
- * body frame...) will be inherited from the template metadata set at writer
- * {@link #EphemerisOemWriter(OemWriter, OdmHeader, OemMetadata, FileFormat, String, double, int) construction}.
- * </p>
- */
- @Override
- public <C extends TimeStampedPVCoordinates, S extends EphemerisFile.EphemerisSegment<C>>
- void write(final Appendable appendable, final EphemerisFile<C, S> ephemerisFile)
- throws IOException {
- if (appendable == null) {
- throw new OrekitIllegalArgumentException(OrekitMessages.NULL_ARGUMENT, "writer");
- }
- if (ephemerisFile == null) {
- return;
- }
- final SatelliteEphemeris<C, S> satEphem = ephemerisFile.getSatellites().get(metadata.getObjectID());
- if (satEphem == null) {
- throw new OrekitIllegalArgumentException(OrekitMessages.VALUE_NOT_FOUND,
- metadata.getObjectID(), "ephemerisFile");
- }
- // Get ephemeris segments to output.
- final List<S> segments = satEphem.getSegments();
- if (segments.isEmpty()) {
- // No data -> No output
- return;
- }
- try (Generator generator = fileFormat == FileFormat.KVN ?
- new KvnGenerator(appendable, OemWriter.KVN_PADDING_WIDTH, outputName,
- maxRelativeOffset, unitsColumn) :
- new XmlGenerator(appendable, XmlGenerator.DEFAULT_INDENT, outputName,
- maxRelativeOffset, unitsColumn > 0, null)) {
- writer.writeHeader(generator, header);
- // Loop on segments
- for (final S segment : segments) {
- writeSegment(generator, segment);
- }
- writer.writeFooter(generator);
- }
- }
- /** Write one segment.
- * @param generator generator to use for producing output
- * @param segment segment to write
- * @param <C> type of the Cartesian coordinates
- * @param <S> type of the segment
- * @throws IOException if any buffer writing operations fails
- */
- public <C extends TimeStampedPVCoordinates, S extends EphemerisFile.EphemerisSegment<C>>
- void writeSegment(final Generator generator, final S segment) throws IOException {
- // override template metadata with segment values
- if (segment instanceof OemSegment) {
- final OemSegment oemSegment = (OemSegment) segment;
- metadata.setReferenceFrame(oemSegment.getMetadata().getReferenceFrame());
- } else {
- metadata.setReferenceFrame(FrameFacade.map(segment.getFrame()));
- }
- metadata.setStartTime(segment.getStart());
- metadata.setStopTime(segment.getStop());
- metadata.setInterpolationDegree(segment.getInterpolationSamples() - 1);
- writer.writeMetadata(generator, metadata);
- // we enter data section
- writer.startData(generator);
- if (segment instanceof OemSegment) {
- // write data comments
- generator.writeComments(((OemSegment) segment).getData().getComments());
- }
- // Loop on orbit data
- final CartesianDerivativesFilter filter = segment.getAvailableDerivatives();
- if (filter == CartesianDerivativesFilter.USE_P) {
- throw new OrekitException(OrekitMessages.MISSING_VELOCITY);
- }
- final boolean useAcceleration = filter.equals(CartesianDerivativesFilter.USE_PVA);
- for (final TimeStampedPVCoordinates coordinates : segment.getCoordinates()) {
- writer.writeOrbitEphemerisLine(generator, metadata, coordinates, useAcceleration);
- }
- if (segment instanceof OemSegment) {
- // output covariance data
- writer.writeCovariances(generator, metadata, ((OemSegment) segment).getCovarianceMatrices());
- }
- // we exit data section
- writer.endData(generator);
- }
- }