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  package org.orekit.files.ccsds.ndm.adm.apm;
18  
19  import org.orekit.errors.OrekitException;
20  import org.orekit.errors.OrekitMessages;
21  import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
22  import org.orekit.files.ccsds.ndm.adm.AttitudeEndpoints;
23  import org.orekit.files.ccsds.section.CommentsContainer;
24  import org.orekit.frames.Frame;
25  
26  /**
27   * Container for Attitude Parameter Message data lines.
28   * <p>
29   * Beware that the Orekit getters and setters all rely on SI units. The parsers
30   * and writers take care of converting these SI units into CCSDS mandatory units.
31   * The {@link org.orekit.utils.units.Unit Unit} class provides useful
32   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
33   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
34   * already use CCSDS units instead of the API SI units. The general-purpose
35   * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
36   * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
37   * (with an 's') also provide some predefined units. These predefined units and the
38   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
39   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
40   * what the parsers and writers use for the conversions.
41   * </p>
42   * @author Bryan Cazabonne
43   * @since 10.2
44   */
45  public class SpinStabilized extends CommentsContainer {
46  
47      /** Endpoints (i.e. frames A, B and their relationship). */
48      private final AttitudeEndpoints endpoints;
49  
50      /** Right ascension of spin axis vector (rad). */
51      private double spinAlpha;
52  
53      /** Declination of the spin axis vector (rad). */
54      private double spinDelta;
55  
56      /** Phase of the satellite about the spin axis (rad). */
57      private double spinAngle;
58  
59      /** Angular velocity of satellite around spin axis (rad/s). */
60      private double spinAngleVel;
61  
62      /** Nutation angle of spin axis (rad). */
63      private double nutation;
64  
65      /** Body nutation period of the spin axis (s). */
66      private double nutationPer;
67  
68      /** Inertial nutation phase (rad). */
69      private double nutationPhase;
70  
71      /** Right ascension of angular momentum vector (rad).
72       * @since 12.0
73       */
74      private double momentumAlpha;
75  
76      /** Declination of the angular momentum vector (rad).
77       * @since 12.0
78       */
79      private double momentumDelta;
80  
81      /** Angular velocity of spin vector around the angular momentum vector (rad/s).
82       * @since 12.0
83       */
84      private double nutationVel;
85  
86      /**
87       * Simple constructor.
88       *
89       * @param frameMapper for creating a {@link Frame}.
90       * @since 13.1.5
91       */
92      public SpinStabilized(final CcsdsFrameMapper frameMapper) {
93          endpoints      = new AttitudeEndpoints(frameMapper);
94          spinAlpha      = Double.NaN;
95          spinDelta      = Double.NaN;
96          spinAngle      = Double.NaN;
97          spinAngleVel   = Double.NaN;
98          nutation       = Double.NaN;
99          nutationPer    = Double.NaN;
100         nutationPhase  = Double.NaN;
101         momentumAlpha  = Double.NaN;
102         momentumDelta  = Double.NaN;
103         nutationVel    = Double.NaN;
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public void validate(final double version) {
109         super.validate(version);
110         endpoints.checkMandatoryEntriesExceptExternalFrame(version,
111                                                            SpinStabilizedKey.SPIN_FRAME_A,
112                                                            SpinStabilizedKey.SPIN_FRAME_B,
113                                                            SpinStabilizedKey.SPIN_DIR);
114         endpoints.checkExternalFrame(SpinStabilizedKey.SPIN_FRAME_A, SpinStabilizedKey.SPIN_FRAME_B);
115         checkNotNaN(spinAlpha,    SpinStabilizedKey.SPIN_ALPHA.name());
116         checkNotNaN(spinDelta,    SpinStabilizedKey.SPIN_DELTA.name());
117         checkNotNaN(spinAngle,    SpinStabilizedKey.SPIN_ANGLE.name());
118         checkNotNaN(spinAngleVel, SpinStabilizedKey.SPIN_ANGLE_VEL.name());
119         if (Double.isNaN(nutation + nutationPer + nutationPhase)) {
120             // if at least one is NaN, all must be NaN (i.e. not initialized)
121             if (!(Double.isNaN(nutation) && Double.isNaN(nutationPer) && Double.isNaN(nutationPhase))) {
122                 throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, "NUTATION*");
123             }
124         }
125         if (Double.isNaN(momentumAlpha + momentumDelta + nutationVel)) {
126             // if at least one is NaN, all must be NaN (i.e. not initialized)
127             if (!(Double.isNaN(momentumAlpha) && Double.isNaN(momentumDelta) && Double.isNaN(nutationVel))) {
128                 throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, "MOMENTUM*/NUTATION_VEL");
129             }
130         }
131     }
132 
133     /** Get the endpoints (i.e. frames A, B and their relationship).
134      * @return endpoints
135      */
136     public AttitudeEndpoints getEndpoints() {
137         return endpoints;
138     }
139 
140     /**
141      * Get the right ascension of spin axis vector (rad).
142      * @return the right ascension of spin axis vector
143      */
144     public double getSpinAlpha() {
145         return spinAlpha;
146     }
147 
148     /**
149      * Set the right ascension of spin axis vector (rad).
150      * @param spinAlpha value to be set
151      */
152     public void setSpinAlpha(final double spinAlpha) {
153         refuseFurtherComments();
154         this.spinAlpha = spinAlpha;
155     }
156 
157     /**
158      * Get the declination of the spin axis vector (rad).
159      * @return the declination of the spin axis vector (rad).
160      */
161     public double getSpinDelta() {
162         return spinDelta;
163     }
164 
165     /**
166      * Set the declination of the spin axis vector (rad).
167      * @param spinDelta value to be set
168      */
169     public void setSpinDelta(final double spinDelta) {
170         refuseFurtherComments();
171         this.spinDelta = spinDelta;
172     }
173 
174     /**
175      * Get the phase of the satellite about the spin axis (rad).
176      * @return the phase of the satellite about the spin axis
177      */
178     public double getSpinAngle() {
179         return spinAngle;
180     }
181 
182     /**
183      * Set the phase of the satellite about the spin axis (rad).
184      * @param spinAngle value to be set
185      */
186     public void setSpinAngle(final double spinAngle) {
187         refuseFurtherComments();
188         this.spinAngle = spinAngle;
189     }
190 
191     /**
192      * Get the angular velocity of satellite around spin axis (rad/s).
193      * @return the angular velocity of satellite around spin axis
194      */
195     public double getSpinAngleVel() {
196         return spinAngleVel;
197     }
198 
199     /**
200      * Set the angular velocity of satellite around spin axis (rad/s).
201      * @param spinAngleVel value to be set
202      */
203     public void setSpinAngleVel(final double spinAngleVel) {
204         refuseFurtherComments();
205         this.spinAngleVel = spinAngleVel;
206     }
207 
208     /**
209      * Get the nutation angle of spin axis (rad).
210      * @return the nutation angle of spin axis
211      */
212     public double getNutation() {
213         return nutation;
214     }
215 
216     /**
217      * Set the nutation angle of spin axis (rad).
218      * @param nutation the nutation angle to be set
219      */
220     public void setNutation(final double nutation) {
221         refuseFurtherComments();
222         this.nutation = nutation;
223     }
224 
225     /**
226      * Get the body nutation period of the spin axis (s).
227      * @return the body nutation period of the spin axis
228      */
229     public double getNutationPeriod() {
230         return nutationPer;
231     }
232 
233     /**
234      * Set the body nutation period of the spin axis (s).
235      * @param period the nutation period to be set
236      */
237     public void setNutationPeriod(final double period) {
238         refuseFurtherComments();
239         this.nutationPer = period;
240     }
241 
242     /**
243      * Get the inertial nutation phase (rad).
244      * @return the inertial nutation phase
245      */
246     public double getNutationPhase() {
247         return nutationPhase;
248     }
249 
250     /**
251      * Set the inertial nutation phase (rad).
252      * @param nutationPhase the nutation phase to be set
253      */
254     public void setNutationPhase(final double nutationPhase) {
255         refuseFurtherComments();
256         this.nutationPhase = nutationPhase;
257     }
258 
259     /**
260      * Get the right ascension of angular momentum vector (rad).
261      * @return the right ascension of angular momentum vector
262      * @since 12.0
263      */
264     public double getMomentumAlpha() {
265         return momentumAlpha;
266     }
267 
268     /**
269      * Set the right ascension of angular momentum vector (rad).
270      * @param momentumAlpha value to be set
271      * @since 12.0
272      */
273     public void setMomentumAlpha(final double momentumAlpha) {
274         refuseFurtherComments();
275         this.momentumAlpha = momentumAlpha;
276     }
277 
278     /**
279      * Get the declination of the angular momentum vector (rad).
280      * @return the declination of the angular momentum vector (rad).
281      * @since 12.0
282      */
283     public double getMomentumDelta() {
284         return momentumDelta;
285     }
286 
287     /**
288      * Set the declination of the angular momentum vector (rad).
289      * @param momentumDelta value to be set
290      * @since 12.0
291      */
292     public void setMomentumDelta(final double momentumDelta) {
293         refuseFurtherComments();
294         this.momentumDelta = momentumDelta;
295     }
296 
297     /**
298      * Get the angular velocity of spin vector around angular momentum vector.
299      * @return angular velocity of spin vector around angular momentum vector (rad/s)
300      * @since 12.0
301      */
302     public double getNutationVel() {
303         return nutationVel;
304     }
305 
306     /**
307      * Set the angular velocity of spin vector around angular momentum vector.
308      * @param nutationVel angular velocity of spin vector around angular momentum vector (rad/s)
309      * @since 12.0
310      */
311     public void setNutationVel(final double nutationVel) {
312         refuseFurtherComments();
313         this.nutationVel = nutationVel;
314     }
315 
316     /** Check if the logical block includes nutation.
317      * @return true if logical block includes nutation
318      * @since 12.0
319      */
320     public boolean hasNutation() {
321         return !Double.isNaN(nutation + nutationPer + nutationPhase);
322     }
323 
324     /** Check if the logical block includes momentum.
325      * @return true if logical block includes momentum
326      * @since 12.0
327      */
328     public boolean hasMomentum() {
329         return !Double.isNaN(momentumAlpha + momentumDelta + nutationVel);
330     }
331 
332 }