1   /* Copyright 2002-2025 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  
18  package org.orekit.files.ccsds.ndm.odm;
19  
20  import org.orekit.bodies.CelestialBodyFactory;
21  import org.orekit.errors.OrekitException;
22  import org.orekit.errors.OrekitMessages;
23  import org.orekit.files.ccsds.definitions.BodyFacade;
24  import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
25  import org.orekit.files.ccsds.definitions.FrameFacade;
26  import org.orekit.files.ccsds.definitions.ModifiedFrame;
27  import org.orekit.files.ccsds.utils.ContextBinding;
28  import org.orekit.frames.Frame;
29  import org.orekit.time.AbsoluteDate;
30  
31  /** Common metadata for Orbit Parameter/Ephemeris/Mean Messages.
32   * @author Luc Maisonobe
33   * @since 11.0
34   */
35  public class OdmCommonMetadata extends OdmMetadata {
36  
37      /** Object identifier of the object for which the orbit state is provided. */
38      private String objectID;
39  
40      /** Origin of reference frame. */
41      private BodyFacade center;
42  
43      /** Reference frame in which data are given: used for state vector
44       * and Keplerian elements data (and for the covariance reference frame if none is given). */
45      private FrameFacade referenceFrame;
46  
47      /** Epoch of reference frame, if not intrinsic to the definition of the
48       * reference frame. */
49      private String frameEpochString;
50  
51      /** Epoch of reference frame, if not intrinsic to the definition of the
52       * reference frame. */
53      private AbsoluteDate frameEpoch;
54  
55      /** Simple constructor.
56       */
57      public OdmCommonMetadata() {
58          super(null);
59      }
60  
61      /** {@inheritDoc} */
62      @Override
63      public void validate(final double version) {
64          super.validate(version);
65          checkNotNull(getObjectName(), OdmMetadataKey.OBJECT_NAME.name());
66          checkNotNull(objectID,        CommonMetadataKey.OBJECT_ID.name());
67          checkNotNull(center,          CommonMetadataKey.CENTER_NAME.name());
68          checkNotNull(referenceFrame,  CommonMetadataKey.REF_FRAME.name());
69      }
70  
71      /** Finalize the metadata.
72       * <p>
73       * ODM standard enforces {@code TIME_SYSTEM} to appear *after*
74       * {@code REF_FRAME_EPOCH}, despite it is needed to interpret it.
75       * We have to wait until parsing end to finalize this date.
76       * </p>
77       * @param context context binding
78       */
79      public void finalizeMetadata(final ContextBinding context) {
80          if (frameEpochString != null) {
81              frameEpoch = context.getTimeSystem().getConverter(context).parse(frameEpochString);
82          }
83      }
84  
85      /** Get the spacecraft ID for which the orbit state is provided.
86       * @return the spacecraft ID
87       */
88      public String getObjectID() {
89          return objectID;
90      }
91  
92      /** Set the spacecraft ID for which the orbit state is provided.
93       * @param objectID the spacecraft ID to be set
94       */
95      public void setObjectID(final String objectID) {
96          refuseFurtherComments();
97          this.objectID = objectID;
98      }
99  
100     /** Get the launch year.
101      * @return launch year
102      */
103     public int getLaunchYear() {
104         return getLaunchYear(objectID);
105     }
106 
107     /** Get the launch number.
108      * @return launch number
109      */
110     public int getLaunchNumber() {
111         return getLaunchNumber(objectID);
112     }
113 
114     /** Get the piece of launch.
115      * @return piece of launch
116      */
117     public String getLaunchPiece() {
118         return getLaunchPiece(objectID);
119     }
120 
121     /** Get the origin of reference frame.
122      * @return the origin of reference frame.
123      */
124     public BodyFacade getCenter() {
125         return center;
126     }
127 
128     /** Set the origin of reference frame.
129      * @param center origin of reference frame to be set
130      */
131     public void setCenter(final BodyFacade center) {
132         refuseFurtherComments();
133         this.center = center;
134     }
135 
136     /**
137      * Get the reference frame in which data are given: used for state vector and
138      * Keplerian elements data (and for the covariance reference frame if none is given).
139      *
140      * @return the reference frame
141      */
142     public Frame getFrame() {
143         if (center.getBody() == null) {
144             throw new OrekitException(OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY, center.getName());
145         }
146         if (referenceFrame.asFrame() == null) {
147             throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, referenceFrame.getName());
148         }
149         // Just return frame if we don't need to shift the center based on CENTER_NAME
150         // MCI and ICRF are the only non-Earth centered frames specified in Annex A.
151         final boolean isMci  = referenceFrame.asCelestialBodyFrame() == CelestialBodyFrame.MCI;
152         final boolean isIcrf = referenceFrame.asCelestialBodyFrame() == CelestialBodyFrame.ICRF;
153         final boolean isSolarSystemBarycenter =
154                 CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER.equals(center.getBody().getName());
155         if (!(isMci || isIcrf) && CelestialBodyFactory.EARTH.equals(center.getBody().getName()) ||
156             isMci && CelestialBodyFactory.MARS.equals(center.getBody().getName()) ||
157             isIcrf && isSolarSystemBarycenter) {
158             return referenceFrame.asFrame();
159         }
160         // else, translate frame to specified center.
161         return new ModifiedFrame(referenceFrame.asFrame(), referenceFrame.asCelestialBodyFrame(),
162                                  center.getBody(), center.getName());
163     }
164 
165     /**
166      * Get the value of {@code REF_FRAME} as an Orekit {@link Frame}. The {@code
167      * CENTER_NAME} key word has not been applied yet, so the returned frame may not
168      * correspond to the reference frame of the data in the file.
169      *
170      * @return The reference frame specified by the {@code REF_FRAME} keyword.
171      * @see #getFrame()
172      */
173     public FrameFacade getReferenceFrame() {
174         return referenceFrame;
175     }
176 
177     /** Set the reference frame in which data are given: used for state vector
178      * and Keplerian elements data (and for the covariance reference frame if none is given).
179      * @param referenceFrame the reference frame to be set
180      */
181     public void setReferenceFrame(final FrameFacade referenceFrame) {
182         refuseFurtherComments();
183         this.referenceFrame = referenceFrame;
184     }
185 
186     /** Set epoch of reference frame, if not intrinsic to the definition of the
187      * reference frame.
188      * @param frameEpochString the epoch of reference frame to be set
189      */
190     public void setFrameEpochString(final String frameEpochString) {
191         refuseFurtherComments();
192         this.frameEpochString = frameEpochString;
193     }
194 
195     /** Get epoch of reference frame, if not intrinsic to the definition of the
196      * reference frame.
197      * @return epoch of reference frame
198      */
199     public AbsoluteDate getFrameEpoch() {
200         return frameEpoch;
201     }
202 
203     /** Set epoch of reference frame, if not intrinsic to the definition of the
204      * reference frame.
205      * @param frameEpoch the epoch of reference frame to be set
206      */
207     public void setFrameEpoch(final AbsoluteDate frameEpoch) {
208         refuseFurtherComments();
209         this.frameEpoch = frameEpoch;
210     }
211 
212 }