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 14.0
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      @Override
38      public Frame buildCcsdsFrame(final FrameFacade orientation,
39                                   final AbsoluteDate frameEpoch) {
40          if (orientation == null) {
41              throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, NO_REFERENCE_FRAME);
42          }
43          final Frame frame = orientation.asFrame();
44          if (frame == null) {
45              throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, orientation.getName());
46          }
47          return frame;
48      }
49  
50      @Override
51      public Frame buildCcsdsFrame(final BodyFacade center,
52                                   final FrameFacade orientation,
53                                   final AbsoluteDate frameEpoch) {
54          if (center == null) {
55              throw new OrekitException(OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY, "No Orbit center name");
56          }
57          final CelestialBody body = center.getBody();
58          if (body == null) {
59              throw new OrekitException(OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY, center.getName());
60          }
61          if (orientation == null) {
62              throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, NO_REFERENCE_FRAME);
63          }
64          final Frame frame = orientation.asFrame();
65          if (frame == null) {
66              throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, orientation.getName());
67          }
68          // Just return frame if we don't need to shift the center based on CENTER_NAME
69          // MCI and ICRF are the only non-Earth centered frames specified in Annex A.
70          final CelestialBodyFrame celestialBodyFrame =
71                  orientation.asCelestialBodyFrame();
72          final boolean isMci = celestialBodyFrame == CelestialBodyFrame.MCI;
73          final boolean isIcrf = celestialBodyFrame == CelestialBodyFrame.ICRF;
74          final String centerName = body.getName();
75          final boolean isCenterEarth = CelestialBodyFactory.EARTH.equals(centerName);
76          final boolean isCenterMars = CelestialBodyFactory.MARS.equals(centerName);
77          if (isIcrf) {
78              // special case so Earth-centered ICRF is GCRF, #1914
79              return body.getIcrfAlignedFrame();
80          }
81          if (!isMci && isCenterEarth || isMci && isCenterMars) {
82              // ICRF and MCI are the only two frames in CelestialBodyFrame
83              // that are not Earth-centered. If that changes then this code would
84              // also need to be updated, perhaps by adding a getCenter() method
85              // to CelestialBodyFrame or Frame.
86              return frame;
87          }
88          // else, translate frame to specified center.
89          return new ModifiedFrame(frame, celestialBodyFrame,
90                  body, center.getName());
91      }
92  
93      @Override
94      public int hashCode() {
95          return this.getClass().hashCode();
96      }
97  
98      @Override
99      public boolean equals(final Object obj) {
100         return this == obj || this.getClass() == OrekitCcsdsFrameMapper.class &&
101                 obj.getClass() == OrekitCcsdsFrameMapper.class;
102     }
103 
104 }