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      @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          final boolean isCenterSsb = CelestialBodyFactory
78                  .SOLAR_SYSTEM_BARYCENTER.equals(centerName);
79          if (isIcrf && isCenterSsb) {
80              // Orekit ICRF is centered on the SSB
81              return frame;
82          }
83          if (isIcrf && isCenterEarth) {
84              // special case so Earth-centered ICRF is GCRF, #1914
85              // hack that uses assumption that GCRF is root frame
86              // full fix in Orekit 14.0
87              Frame f = frame;
88              while (f.getDepth() != 0) {
89                  f = f.getParent();
90              }
91              return f;
92          }
93          if (!isMci && isCenterEarth || isMci && isCenterMars) {
94              // ICRF and MCI are the only two frames in CelestialBodyFrame
95              // that are not Earth-centered. If that changes then this code would
96              // also need to be updated, perhaps by adding a getCenter() method
97              // to CelestialBodyFrame or Frame.
98              return frame;
99          }
100         // else, translate frame to specified center.
101         return new ModifiedFrame(frame, celestialBodyFrame,
102                 body, center.getName());
103     }
104 
105     @Override
106     public int hashCode() {
107         return this.getClass().hashCode();
108     }
109 
110     @Override
111     public boolean equals(final Object obj) {
112         return this == obj || this.getClass() == OrekitCcsdsFrameMapper.class &&
113                 obj.getClass() == OrekitCcsdsFrameMapper.class;
114     }
115 
116 }