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;
18
19 import java.util.Arrays;
20 import java.util.Optional;
21
22 import org.hipparchus.complex.Quaternion;
23 import org.orekit.annotation.Nullable;
24 import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
25 import org.orekit.files.ccsds.definitions.FrameFacade;
26 import org.orekit.files.ccsds.ndm.cdm.AdditionalParameters;
27 import org.orekit.files.ccsds.ndm.odm.ocm.OrbitPhysicalProperties;
28 import org.orekit.files.ccsds.section.CommentsContainer;
29 import org.orekit.frames.Frame;
30 import org.orekit.time.AbsoluteDate;
31
32 /** Container for common physical properties for both {@link OrbitPhysicalProperties} and {@link AdditionalParameters}.
33 * <p>
34 * Beware that the Orekit getters and setters all rely on SI units. The parsers
35 * and writers take care of converting these SI units into CCSDS mandatory units.
36 * The {@link org.orekit.utils.units.Unit Unit} class provides useful
37 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
38 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
39 * already use CCSDS units instead of the API SI units. The general-purpose
40 * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
41 * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
42 * (with an 's') also provide some predefined units. These predefined units and the
43 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
44 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
45 * what the parsers and writers use for the conversions.
46 * </p>
47 * @author Maxime Journot
48 * @since 11.3
49 */
50 public class CommonPhysicalProperties extends CommentsContainer {
51
52 /** For creating a {@link Frame}. */
53 private final CcsdsFrameMapper frameMapper;
54
55 /** Optimally Enclosing Box parent reference frame. */
56 private FrameFacade oebParentFrame;
57
58 /** Optimally Enclosing Box parent reference frame epoch. */
59 @Nullable
60 private AbsoluteDate oebParentFrameEpoch;
61
62 /** Quaternion defining Optimally Enclosing Box. */
63 @Nullable
64 private double[] oebQ;
65
66 /** Maximum physical dimension of Optimally Enclosing Box. */
67 @Nullable
68 private Double oebMax;
69
70 /** Intermediate physical dimension of Optimally Enclosing Box. */
71 @Nullable
72 private Double oebIntermediate;
73
74 /** Minimum physical dimension of Optimally Enclosing Box. */
75 @Nullable
76 private Double oebMin;
77
78 /** Cross-sectional area of Optimally Enclosing Box when viewed along the maximum OEB direction. */
79 @Nullable
80 private Double oebAreaAlongMax;
81
82 /** Cross-sectional area of Optimally Enclosing Box when viewed along the intermediate OEB direction. */
83 @Nullable
84 private Double oebAreaAlongIntermediate;
85
86 /** Cross-sectional area of Optimally Enclosing Box when viewed along the minimum OEB direction. */
87 @Nullable
88 private Double oebAreaAlongMin;
89
90 /** Typical (50th percentile) radar cross-section. */
91 @Nullable
92 private Double rcs;
93
94 /** Minimum radar cross-section. */
95 @Nullable
96 private Double minRcs;
97
98 /** Maximum radar cross-section. */
99 @Nullable
100 private Double maxRcs;
101
102 /** Typical (50th percentile) visual magnitude. */
103 @Nullable
104 private Double vmAbsolute;
105
106 /** Minimum apparent visual magnitude. */
107 @Nullable
108 private Double vmApparentMin;
109
110 /** Typical (50th percentile) apparent visual magnitude. */
111 @Nullable
112 private Double vmApparent;
113
114 /** Maximum apparent visual magnitude. */
115 @Nullable
116 private Double vmApparentMax;
117
118 /** Typical (50th percentile) coefficient of reflectivity. */
119 @Nullable
120 private Double reflectance;
121
122 /**
123 * Simple constructor.
124 *
125 * @param epochT0 T0 epoch from file metadata
126 * @param frameMapper for creating a {@link Frame}.
127 * @since 13.1.5
128 */
129 public CommonPhysicalProperties(final AbsoluteDate epochT0, final CcsdsFrameMapper frameMapper) {
130 // 502.0-B-3 (page 6-23) says the default is RSW_ROTATING, but also says,
131 // "This keyword shall be provided if OEB_Q1,2,3,4 are specified".
132 // Which means it must be specified in the file any time it would be used,
133 // which leaves the default without any effect.
134 this.frameMapper = frameMapper;
135 oebParentFrame = new FrameFacade(null, null, null, null, null);
136 // 502.0-B-3 (page 6-23) says the default is EPOCH_TZERO from the OCM metadata.
137 oebParentFrameEpoch = epochT0;
138 }
139
140 /** Get the Optimally Enclosing Box parent reference frame.
141 * @return Optimally Enclosing Box parent reference frame
142 */
143 public FrameFacade getOebParentFrame() {
144 return oebParentFrame;
145 }
146
147 /** Set the Optimally Enclosing Box parent reference frame.
148 * @param oebParentFrame Optimally Enclosing Box parent reference frame
149 */
150 public void setOebParentFrame(final FrameFacade oebParentFrame) {
151 refuseFurtherComments();
152 this.oebParentFrame = oebParentFrame;
153 }
154
155 /** Get the Optimally Enclosing Box parent reference frame epoch.
156 * @return Optimally Enclosing Box parent reference frame epoch
157 */
158 public Optional<AbsoluteDate> getOebParentFrameEpoch() {
159 return Optional.ofNullable(oebParentFrameEpoch);
160 }
161
162 /** Set the Optimally Enclosing Box parent reference frame epoch.
163 * @param oebParentFrameEpoch Optimally Enclosing Box parent reference frame epoch
164 */
165 public void setOebParentFrameEpoch(final AbsoluteDate oebParentFrameEpoch) {
166 refuseFurtherComments();
167 this.oebParentFrameEpoch = oebParentFrameEpoch;
168 }
169
170 /**
171 * Get the mapping between a CCSDS frame and a {@link Frame}.
172 *
173 * @return the frame mapper.
174 * @since 13.1.5
175 */
176 public CcsdsFrameMapper getFrameMapper() {
177 return frameMapper;
178 }
179
180 /**
181 * Get the frame OEB parent frame. Note that only the orientation of the
182 * returned frame is significant, the position of the returned frame is
183 * irrelevant and should be ignored.
184 *
185 * @return Orekit frame for this covariance history.
186 * @see #getOebParentFrame()
187 * @see #getOebParentFrameEpoch()
188 * @see #getFrameMapper()
189 * @since 13.1.5
190 */
191 public Frame getOebParent() {
192 return getFrameMapper().buildCcsdsFrame(oebParentFrame, oebParentFrameEpoch);
193 }
194
195 /** Get the quaternion defining Optimally Enclosing Box.
196 * @return quaternion defining Optimally Enclosing Box
197 */
198 public Optional<Quaternion> getOebQ() {
199 if (oebQ == null) {
200 return Optional.empty();
201 }
202 return Optional.of(new Quaternion(oebQ[0], oebQ[1], oebQ[2], oebQ[3]));
203 }
204
205 /** set the component of quaternion defining Optimally Enclosing Box.
206 * @param i index of the component
207 * @param qI component of quaternion defining Optimally Enclosing Box
208 */
209 public void setOebQ(final int i, final double qI) {
210 refuseFurtherComments();
211 if (oebQ == null) {
212 oebQ = new double[4];
213 Arrays.fill(oebQ, Double.NaN);
214 }
215 oebQ[i] = qI;
216 }
217
218 /** Get the maximum physical dimension of the OEB.
219 * @return maximum physical dimension of the OEB.
220 */
221 public Optional<Double> getOebMax() {
222 return Optional.ofNullable(oebMax);
223 }
224
225 /** Set the maximum physical dimension of the OEB.
226 * @param oebMax maximum physical dimension of the OEB.
227 */
228 public void setOebMax(final double oebMax) {
229 refuseFurtherComments();
230 this.oebMax = oebMax;
231 }
232
233 /** Get the intermediate physical dimension of the OEB.
234 * @return intermediate physical dimension of the OEB.
235 */
236 public Optional<Double> getOebIntermediate() {
237 return Optional.ofNullable(oebIntermediate);
238 }
239
240 /** Set the intermediate physical dimension of the OEB.
241 * @param oebIntermediate intermediate physical dimension of the OEB.
242 */
243 public void setOebIntermediate(final double oebIntermediate) {
244 refuseFurtherComments();
245 this.oebIntermediate = oebIntermediate;
246 }
247
248 /** Get the minimum physical dimension of the OEB.
249 * @return dimensions the minimum physical dimension of the OEB.
250 */
251 public Optional<Double> getOebMin() {
252 return Optional.ofNullable(oebMin);
253 }
254
255 /** Set the minimum physical dimension of the OEB.
256 * @param oebMin the minimum physical dimension of the OEB.
257 */
258 public void setOebMin(final double oebMin) {
259 refuseFurtherComments();
260 this.oebMin = oebMin;
261 }
262
263 /** Get the cross-sectional area of Optimally Enclosing Box when viewed along the maximum OEB direction.
264 * @return cross-sectional area of Optimally Enclosing Box when viewed along the maximum OEB direction.
265 */
266 public Optional<Double> getOebAreaAlongMax() {
267 return Optional.ofNullable(oebAreaAlongMax);
268 }
269
270 /** Set the cross-sectional area of Optimally Enclosing Box when viewed along the maximum OEB direction.
271 * @param oebAreaAlongMax cross-sectional area of Optimally Enclosing Box when viewed along the maximum OEB direction.
272 */
273 public void setOebAreaAlongMax(final double oebAreaAlongMax) {
274 refuseFurtherComments();
275 this.oebAreaAlongMax = oebAreaAlongMax;
276 }
277
278 /** Get the cross-sectional area of Optimally Enclosing Box when viewed along the intermediate OEB direction.
279 * @return cross-sectional area of Optimally Enclosing Box when viewed along the intermediate OEB direction.
280 */
281 public Optional<Double> getOebAreaAlongIntermediate() {
282 return Optional.ofNullable(oebAreaAlongIntermediate);
283 }
284
285 /** Set the cross-sectional area of Optimally Enclosing Box when viewed along the intermediate OEB direction.
286 * @param oebAreaAlongIntermediate cross-sectional area of Optimally Enclosing Box when viewed along the intermediate OEB direction.
287 */
288 public void setOebAreaAlongIntermediate(final double oebAreaAlongIntermediate) {
289 refuseFurtherComments();
290 this.oebAreaAlongIntermediate = oebAreaAlongIntermediate;
291 }
292
293 /** Get the cross-sectional area of Optimally Enclosing Box when viewed along the minimum OEB direction.
294 * @return cross-sectional area of Optimally Enclosing Box when viewed along the minimum OEB direction.
295 */
296 public Optional<Double> getOebAreaAlongMin() {
297 return Optional.ofNullable(oebAreaAlongMin);
298 }
299
300 /** Set the cross-sectional area of Optimally Enclosing Box when viewed along the minimum OEB direction.
301 * @param oebAreaAlongMin cross-sectional area of Optimally Enclosing Box when viewed along the minimum OEB direction.
302 */
303 public void setOebAreaAlongMin(final double oebAreaAlongMin) {
304 refuseFurtherComments();
305 this.oebAreaAlongMin = oebAreaAlongMin;
306 }
307
308
309 /** Get the typical (50th percentile) radar cross-section.
310 * @return typical (50th percentile) radar cross-section
311 */
312 public Optional<Double> getRcs() {
313 return Optional.ofNullable(rcs);
314 }
315
316 /** Set the typical (50th percentile) radar cross-section.
317 * @param rcs typical (50th percentile) radar cross-section
318 */
319 public void setRcs(final double rcs) {
320 refuseFurtherComments();
321 this.rcs = rcs;
322 }
323
324 /** Get the minimum radar cross-section.
325 * @return minimum radar cross-section
326 */
327 public Optional<Double> getMinRcs() {
328 return Optional.ofNullable(minRcs);
329 }
330
331 /** Set the minimum radar cross-section.
332 * @param minRcs minimum radar cross-section
333 */
334 public void setMinRcs(final double minRcs) {
335 refuseFurtherComments();
336 this.minRcs = minRcs;
337 }
338
339 /** Get the maximum radar cross-section.
340 * @return maximum radar cross-section
341 */
342 public Optional<Double> getMaxRcs() {
343 return Optional.ofNullable(maxRcs);
344 }
345
346 /** Set the maximum radar cross-section.
347 * @param maxRcs maximum radar cross-section
348 */
349 public void setMaxRcs(final double maxRcs) {
350 refuseFurtherComments();
351 this.maxRcs = maxRcs;
352 }
353
354 /** Get the typical (50th percentile) visual magnitude.
355 * @return typical (50th percentile) visual magnitude
356 */
357 public Optional<Double> getVmAbsolute() {
358 return Optional.ofNullable(vmAbsolute);
359 }
360
361 /** Set the typical (50th percentile) visual magnitude.
362 * @param vmAbsolute typical (50th percentile) visual magnitude
363 */
364 public void setVmAbsolute(final double vmAbsolute) {
365 refuseFurtherComments();
366 this.vmAbsolute = vmAbsolute;
367 }
368
369 /** Get the minimum apparent visual magnitude.
370 * @return minimum apparent visual magnitude
371 */
372 public Optional<Double> getVmApparentMin() {
373 return Optional.ofNullable(vmApparentMin);
374 }
375
376 /** Set the minimum apparent visual magnitude.
377 * @param vmApparentMin minimum apparent visual magnitude
378 */
379 public void setVmApparentMin(final double vmApparentMin) {
380 refuseFurtherComments();
381 this.vmApparentMin = vmApparentMin;
382 }
383
384 /** Get the typical (50th percentile) apparent visual magnitude.
385 * @return typical (50th percentile) apparent visual magnitude
386 */
387 public Optional<Double> getVmApparent() {
388 return Optional.ofNullable(vmApparent);
389 }
390
391 /** Set the typical (50th percentile) apparent visual magnitude.
392 * @param vmApparent typical (50th percentile) apparent visual magnitude
393 */
394 public void setVmApparent(final double vmApparent) {
395 refuseFurtherComments();
396 this.vmApparent = vmApparent;
397 }
398
399 /** Get the maximum apparent visual magnitude.
400 * @return maximum apparent visual magnitude
401 */
402 public Optional<Double> getVmApparentMax() {
403 return Optional.ofNullable(vmApparentMax);
404 }
405
406 /** Set the maximum apparent visual magnitude.
407 * @param vmApparentMax maximum apparent visual magnitude
408 */
409 public void setVmApparentMax(final double vmApparentMax) {
410 refuseFurtherComments();
411 this.vmApparentMax = vmApparentMax;
412 }
413
414 /** Get the typical (50th percentile) coefficient of reflectance.
415 * @return typical (50th percentile) coefficient of reflectance
416 */
417 public Optional<Double> getReflectance() {
418 return Optional.ofNullable(reflectance);
419 }
420
421 /** Set the typical (50th percentile) coefficient of reflectance.
422 * @param reflectance typical (50th percentile) coefficient of reflectance
423 */
424 public void setReflectance(final double reflectance) {
425 refuseFurtherComments();
426 this.reflectance = reflectance;
427 }
428 }