1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.adm;
18
19 import java.util.Optional;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.Field;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.orekit.annotation.Nullable;
25 import org.orekit.attitudes.Attitude;
26 import org.orekit.attitudes.AttitudeBuilder;
27 import org.orekit.attitudes.FieldAttitude;
28 import org.orekit.errors.OrekitException;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
31 import org.orekit.files.ccsds.definitions.FrameFacade;
32 import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
33 import org.orekit.frames.Frame;
34 import org.orekit.utils.AngularCoordinates;
35 import org.orekit.utils.FieldAngularCoordinates;
36 import org.orekit.utils.FieldPVCoordinates;
37 import org.orekit.utils.FieldPVCoordinatesProvider;
38 import org.orekit.utils.PVCoordinates;
39 import org.orekit.utils.PVCoordinatesProvider;
40 import org.orekit.utils.TimeStampedAngularCoordinates;
41 import org.orekit.utils.TimeStampedFieldAngularCoordinates;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class AttitudeEndpoints implements AttitudeBuilder {
58
59
60 public static final String A2B = "A2B";
61
62
63 public static final String B2A = "B2A";
64
65
66 private final CcsdsFrameMapper frameMapper;
67
68
69 private FrameFacade frameA;
70
71
72 private FrameFacade frameB;
73
74
75 @Nullable
76 private Boolean a2b;
77
78
79
80
81
82
83
84 public AttitudeEndpoints(final CcsdsFrameMapper frameMapper) {
85 this.frameMapper = frameMapper;
86 }
87
88
89
90
91
92 private void checkNotNull(final Object field, final Enum<?> key) {
93 if (field == null) {
94 throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, key.name());
95 }
96 }
97
98
99
100
101 public void checkExternalFrame(final Enum<?> aKey, final Enum<?> bKey) {
102 checkNotNull(frameA, aKey);
103 checkNotNull(frameB, bKey);
104 if (frameA.asSpacecraftBodyFrame().isPresent() && frameB.asSpacecraftBodyFrame().isPresent()) {
105
106 throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, frameB.getName());
107 }
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 public void checkMandatoryEntriesExceptExternalFrame(final double version,
124 final Enum<?> aKey, final Enum<?> bKey,
125 final Enum<?> dirKey) {
126
127 if (frameA == null) {
128 if (frameB == null || frameB.asSpacecraftBodyFrame().isEmpty()) {
129 throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, aKey.name());
130 }
131 } else if (frameA.asSpacecraftBodyFrame().isEmpty()) {
132 if (frameB == null) {
133 throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, bKey.name());
134 } else if (frameB.asSpacecraftBodyFrame().isEmpty()) {
135
136 throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, frameB.getName());
137 }
138 }
139
140 if (version < 2.0) {
141
142 checkNotNull(a2b, dirKey);
143 } else if (!isA2b()) {
144
145 throw new OrekitException(OrekitMessages.CCSDS_KEYWORD_NOT_ALLOWED_IN_VERSION,
146 dirKey, version);
147 }
148
149 }
150
151
152
153
154 public void setFrameA(final FrameFacade frameA) {
155 this.frameA = frameA;
156 }
157
158
159
160
161 public FrameFacade getFrameA() {
162 return frameA;
163 }
164
165
166
167
168 public void setFrameB(final FrameFacade frameB) {
169 this.frameB = frameB;
170 }
171
172
173
174
175 public FrameFacade getFrameB() {
176 return frameB;
177 }
178
179
180
181
182
183 public void setA2b(final boolean a2b) {
184 this.a2b = a2b;
185 }
186
187
188
189
190 public boolean isA2b() {
191 return a2b == null ? true : a2b;
192 }
193
194
195
196
197
198 public FrameFacade getExternalFrame() {
199 return frameA.asSpacecraftBodyFrame().isEmpty() ? frameA : frameB;
200 }
201
202
203
204
205
206
207
208 public CcsdsFrameMapper getFrameMapper() {
209 return frameMapper;
210 }
211
212
213
214
215
216
217
218
219 public Frame getExternal() {
220
221 return getFrameMapper().buildCcsdsFrame(getExternalFrame(), null);
222 }
223
224
225
226
227 public FrameFacade getSpacecraftBodyFrame() {
228 return frameA.asSpacecraftBodyFrame().isEmpty() ? frameB : frameA;
229 }
230
231
232
233
234
235
236
237
238
239
240 public boolean isExternal2SpacecraftBody() {
241 return isA2b() ^ frameB.asSpacecraftBodyFrame().isEmpty();
242 }
243
244
245
246
247
248
249
250
251
252 public boolean isCompatibleWith(final AttitudeEndpoints other) {
253 return frameA.getName().equals(other.frameA.getName()) &&
254 frameB.getName().equals(other.frameB.getName()) &&
255 a2b.equals(other.a2b);
256 }
257
258
259 @Override
260 public Attitude build(final Frame frame, final PVCoordinatesProvider pvProv,
261 final TimeStampedAngularCoordinates rawAttitude) {
262
263
264 final TimeStampedAngularCoordinates att =
265 isExternal2SpacecraftBody() ? rawAttitude : rawAttitude.revert();
266
267 final FrameFacade external = getExternalFrame();
268 final Optional<OrbitRelativeFrame> orf = external.asOrbitRelativeFrame();
269 if (orf.isPresent()) {
270
271 if (orf.get().getLofType() == null) {
272 throw new OrekitException(OrekitMessages.UNSUPPORTED_LOCAL_ORBITAL_FRAME, external.getName());
273 }
274
275
276 final PVCoordinates pv = pvProv.getPVCoordinates(rawAttitude.getDate(), frame);
277 final AngularCoordinates frame2Lof =
278 orf.get().isQuasiInertial() ?
279 new AngularCoordinates(orf.get().getLofType().rotationFromInertial(pv)) :
280 orf.get().getLofType().transformFromInertial(att.getDate(), pv).getAngular();
281
282
283 return new Attitude(frame, att.addOffset(frame2Lof));
284
285 } else {
286
287 final Frame externalFrame = external.
288 asFrame().
289 orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME,
290 external.getName()));
291 final Attitude attitude = new Attitude(externalFrame, att);
292 return frame == null ? attitude : attitude.withReferenceFrame(frame);
293 }
294
295 }
296
297
298 @Override
299 public <T extends CalculusFieldElement<T>>
300 FieldAttitude<T> build(final Frame frame, final FieldPVCoordinatesProvider<T> pvProv,
301 final TimeStampedFieldAngularCoordinates<T> rawAttitude) {
302
303
304 final TimeStampedFieldAngularCoordinates<T> att =
305 isExternal2SpacecraftBody() ? rawAttitude : rawAttitude.revert();
306
307 final FrameFacade external = getExternalFrame();
308 final Optional<OrbitRelativeFrame> orf = external.asOrbitRelativeFrame();
309 if (orf.isPresent()) {
310
311 if (orf.get().getLofType() == null) {
312 throw new OrekitException(OrekitMessages.UNSUPPORTED_LOCAL_ORBITAL_FRAME, external.getName());
313 }
314
315
316 final FieldPVCoordinates<T> pv = pvProv.getPVCoordinates(rawAttitude.getDate(), frame);
317 final Field<T> field = rawAttitude.getDate().getField();
318 final FieldAngularCoordinates<T> referenceToLof =
319 orf.get().isQuasiInertial() ?
320 new FieldAngularCoordinates<>(orf.get().getLofType().rotationFromInertial(field, pv),
321 FieldVector3D.getZero(field)) :
322 orf.get().getLofType().transformFromInertial(att.getDate(), pv).getAngular();
323
324
325 return new FieldAttitude<>(frame, att.addOffset(referenceToLof));
326
327 } else {
328
329
330 final Frame externalFrame = external.
331 asFrame().
332 orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME,
333 external.getName()));
334 final FieldAttitude<T> attitude = new FieldAttitude<>(externalFrame, att);
335 return frame == null ? attitude : attitude.withReferenceFrame(frame);
336 }
337
338 }
339
340
341 @Override
342 public String toString() {
343 return frameA.getName() + (isA2b() ? " → " : " ← ") + frameB.getName();
344 }
345
346 }