1   /* Contributed in the public domain.
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.definitions;
18  
19  import org.orekit.bodies.CelestialBody;
20  import org.orekit.bodies.CelestialBodyFactory;
21  import org.orekit.errors.OrekitException;
22  import org.orekit.errors.OrekitMessages;
23  import org.orekit.frames.Frame;
24  import org.orekit.time.AbsoluteDate;
25  
26  /**
27   * Orekit's default implementation of {@link CcsdsFrameMapper}.
28   *
29   * @author Evan M. Ward
30   * @since 13.1.5
31   */
32  public class OrekitCcsdsFrameMapper implements CcsdsFrameMapper {
33  
34      /** Message indicating no reference frame. */
35      private static final String NO_REFERENCE_FRAME = "No reference frame";
36  
37      /** Simple constructor. */
38      public OrekitCcsdsFrameMapper() {
39          // nothing to do
40      }
41  
42      @Override
43      public Frame buildCcsdsFrame(final FrameFacade orientation,
44                                   final AbsoluteDate frameEpoch) {
45          if (orientation == null) {
46              throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, NO_REFERENCE_FRAME);
47          }
48          return orientation.asFrame().
49              orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, orientation.getName()));
50  
51      }
52  
53      @Override
54      public Frame buildCcsdsFrame(final BodyFacade center,
55                                   final FrameFacade orientation,
56                                   final AbsoluteDate frameEpoch) {
57          if (center == null) {
58              throw new OrekitException(OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY, "No Orbit center name");
59          }
60          final CelestialBody body =
61              center.
62                  getBody().
63                  orElseThrow(() -> new OrekitException(OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY,
64                                                        center.getName()));
65          if (orientation == null) {
66              throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, NO_REFERENCE_FRAME);
67          }
68          final Frame frame =
69              orientation.asFrame().
70                  orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, orientation.getName()));
71          // Just return frame if we don't need to shift the center based on CENTER_NAME
72          // MCI and ICRF are the only non-Earth centered frames specified in Annex A.
73          final CelestialBodyFrame celestialBodyFrame = orientation.asCelestialBodyFrame().orElse(null);
74          final boolean isMci = celestialBodyFrame == CelestialBodyFrame.MCI;
75          final boolean isIcrf = celestialBodyFrame == CelestialBodyFrame.ICRF;
76          final String centerName = center.getBody().get().getName();
77          final boolean isCenterEarth = CelestialBodyFactory.EARTH.equals(centerName);
78          final boolean isCenterMars = CelestialBodyFactory.MARS.equals(centerName);
79          if (isIcrf) {
80              // special case so Earth-centered ICRF is GCRF, #1914
81              return body.getIcrfAlignedFrame();
82          }
83          if (!isMci && isCenterEarth || isMci && isCenterMars) {
84              // ICRF and MCI are the only two frames in CelestialBodyFrame
85              // that are not Earth-centered. If that changes then this code would
86              // also need to be updated, perhaps by adding a getCenter() method
87              // to CelestialBodyFrame or Frame.
88              return frame;
89          }
90          // else, translate frame to specified center.
91          return new ModifiedFrame(frame, celestialBodyFrame,
92                  body, center.getName());
93      }
94  
95      @Override
96      public int hashCode() {
97          return this.getClass().hashCode();
98      }
99  
100     @Override
101     public boolean equals(final Object obj) {
102         return this == obj || this.getClass() == OrekitCcsdsFrameMapper.class &&
103                 obj.getClass() == OrekitCcsdsFrameMapper.class;
104     }
105 
106 }