1   /* Copyright 2002-2026 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 java.util.Optional;
21  
22  import org.orekit.annotation.Nullable;
23  import org.orekit.files.ccsds.section.CommentsContainer;
24  import org.orekit.files.ccsds.section.Data;
25  import org.orekit.frames.Frame;
26  import org.orekit.orbits.KeplerianOrbit;
27  import org.orekit.orbits.PositionAngleType;
28  import org.orekit.time.AbsoluteDate;
29  
30  /** Container for Keplerian elements.
31   * <p>
32   * Beware that the Orekit getters and setters all rely on SI units. The parsers
33   * and writers take care of converting these SI units into CCSDS mandatory units.
34   * The {@link org.orekit.utils.units.Unit Unit} class provides useful
35   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
36   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
37   * already use CCSDS units instead of the API SI units. The general-purpose
38   * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
39   * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
40   * (with an 's') also provide some predefined units. These predefined units and the
41   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
42   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
43   * what the parsers and writers use for the conversions.
44   * </p>
45   * @author sports
46   * @since 6.1
47   */
48  public class KeplerianElements extends CommentsContainer implements Data {
49  
50      /** Epoch of state vector and optional Keplerian elements. */
51      private AbsoluteDate epoch;
52  
53      /** Orbit semi-major axis (m).
54       * <p>
55       * Used in OPM instead of mean motion.
56       * </p>
57       */
58      @Nullable
59      private Double a;
60  
61      /** Mean motion (the Keplerian Mean motion in rad/s).
62       * <p>
63       * Used in OMM instead of semi-major axis if MEAN_ELEMENT_THEORY = SGP/SGP4.
64       * </p>
65       */
66      @Nullable
67      private Double meanMotion;
68  
69      /** Orbit eccentricity. */
70      private double e;
71  
72      /** Orbit inclination (rad). */
73      private double i;
74  
75      /** Orbit right ascension of ascending node (rad). */
76      private double raan;
77  
78      /** Orbit argument of pericenter (rad). */
79      private double pa;
80  
81      /** Orbit anomaly (rad). */
82      private double anomaly;
83  
84      /** Orbit anomaly type (mean or true). */
85      private PositionAngleType anomalyType;
86  
87      /** Gravitational coefficient. */
88      @Nullable
89      private Double mu;
90  
91      /** Simple constructor.
92       */
93      public KeplerianElements() {
94          e          = Double.NaN;
95          i          = Double.NaN;
96          raan       = Double.NaN;
97          pa         = Double.NaN;
98          anomaly    = Double.NaN;
99      }
100 
101     /** {@inheritDoc}
102      * <p>
103      * We check neither semi-major axis nor mean motion here,
104      * they must be checked separately in OPM and OMM parsers
105      * </p>
106      */
107     @Override
108     public void validate(final double version) {
109         super.validate(version);
110         checkNotNull(epoch,  StateVectorKey.EPOCH.name());
111         checkNotNaN(e,       KeplerianElementsKey.ECCENTRICITY.name());
112         checkNotNaN(i,       KeplerianElementsKey.INCLINATION.name());
113         checkNotNaN(raan,    KeplerianElementsKey.RA_OF_ASC_NODE.name());
114         checkNotNaN(pa,      KeplerianElementsKey.ARG_OF_PERICENTER.name());
115         checkNotNaN(anomaly, KeplerianElementsKey.MEAN_ANOMALY.name());
116     }
117 
118     /** Get epoch of state vector, Keplerian elements and covariance matrix data.
119      * @return epoch the epoch
120      */
121     public AbsoluteDate getEpoch() {
122         return epoch;
123     }
124 
125     /** Set epoch of state vector, Keplerian elements and covariance matrix data.
126      * @param epoch the epoch to be set
127      */
128     public void setEpoch(final AbsoluteDate epoch) {
129         refuseFurtherComments();
130         this.epoch = epoch;
131     }
132 
133     /** Get the orbit semi-major axis.
134      * @return the orbit semi-major axis
135      */
136     public Optional<Double> getA() {
137         return Optional.ofNullable(a);
138     }
139 
140     /** Set the orbit semi-major axis.
141      * @param a the semi-major axis to be set
142      */
143     public void setA(final double a) {
144         refuseFurtherComments();
145         this.a = a;
146     }
147 
148     /** Get the orbit mean motion.
149      * @return the orbit mean motion
150      */
151     public Optional<Double> getMeanMotion() {
152         return Optional.ofNullable(meanMotion);
153     }
154 
155     /** Set the orbit mean motion.
156      * @param motion the mean motion to be set
157      */
158     public void setMeanMotion(final double motion) {
159         this.meanMotion = motion;
160     }
161 
162     /** Get the orbit eccentricity.
163      * @return the orbit eccentricity
164      */
165     public double getE() {
166         return e;
167     }
168 
169     /** Set the orbit eccentricity.
170      * @param e the eccentricity to be set
171      */
172     public void setE(final double e) {
173         refuseFurtherComments();
174         this.e = e;
175     }
176 
177     /** Get the orbit inclination.
178      * @return the orbit inclination
179      */
180     public double getI() {
181         return i;
182     }
183 
184     /**Set the orbit inclination.
185      * @param i the inclination to be set
186      */
187     public void setI(final double i) {
188         refuseFurtherComments();
189         this.i = i;
190     }
191 
192     /** Get the orbit right ascension of ascending node.
193      * @return the orbit right ascension of ascending node
194      */
195     public double getRaan() {
196         return raan;
197     }
198 
199     /** Set the orbit right ascension of ascending node.
200      * @param raan the right ascension of ascending node to be set
201      */
202     public void setRaan(final double raan) {
203         refuseFurtherComments();
204         this.raan = raan;
205     }
206 
207     /** Get the orbit argument of pericenter.
208      * @return the orbit argument of pericenter
209      */
210     public double getPa() {
211         return pa;
212     }
213 
214     /** Set the orbit argument of pericenter.
215      * @param pa the argument of pericenter to be set
216      */
217     public void setPa(final double pa) {
218         refuseFurtherComments();
219         this.pa = pa;
220     }
221 
222     /** Get the orbit anomaly.
223      * @return the orbit anomaly
224      */
225     public double getAnomaly() {
226         return anomaly;
227     }
228 
229     /** Set the orbit anomaly.
230      * @param anomaly the anomaly to be set
231      */
232     public void setAnomaly(final double anomaly) {
233         refuseFurtherComments();
234         this.anomaly = anomaly;
235     }
236 
237     /** Get the type of anomaly (true or mean).
238      * @return the type of anomaly
239      */
240     public PositionAngleType getAnomalyType() {
241         return anomalyType;
242     }
243 
244     /** Set the type of anomaly.
245      * @param anomalyType the type of anomaly to be set
246      */
247     public void setAnomalyType(final PositionAngleType anomalyType) {
248         refuseFurtherComments();
249         this.anomalyType = anomalyType;
250     }
251 
252     /**
253      * Set the gravitational coefficient.
254      * @param mu the coefficient to be set
255      */
256     public void setMu(final double mu) {
257         refuseFurtherComments();
258         this.mu = mu;
259     }
260 
261     /**
262      * Get the gravitational coefficient.
263      * @return gravitational coefficient
264      */
265     public Optional<Double> getMu() {
266         return Optional.ofNullable(mu);
267     }
268 
269     /** Generate a keplerian orbit.
270      * @param frame inertial frame for orbit
271      * @param defaultMu default gravitational coefficient to use if not specified in the file
272      * @return generated orbit
273      */
274     public KeplerianOrbit generateKeplerianOrbit(final Frame frame, final double defaultMu) {
275         return new KeplerianOrbit(a, e, i, pa, raan, anomaly, anomalyType, frame, epoch, getMu().orElse(defaultMu));
276     }
277 
278 }