1 /* Copyright 2002-2024 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.definitions; 18 19 import org.hipparchus.geometry.euclidean.threed.Rotation; 20 import org.orekit.data.DataContext; 21 import org.orekit.errors.OrekitException; 22 import org.orekit.errors.OrekitMessages; 23 import org.orekit.frames.Frame; 24 import org.orekit.frames.LOFType; 25 import org.orekit.frames.Transform; 26 import org.orekit.time.AbsoluteDate; 27 import org.orekit.utils.IERSConventions; 28 import org.orekit.utils.PVCoordinatesProvider; 29 30 /** Facade in front of several frames types in CCSDS messages. 31 * 32 * @author Luc Maisonobe 33 * @author Vincent Cucchietti 34 * @since 11.0 35 */ 36 public class FrameFacade { 37 38 /** Reference to node in Orekit frames tree. */ 39 private final Frame frame; 40 41 /** Reference to celestial body centered frame. */ 42 private final CelestialBodyFrame celestialBodyFrame; 43 44 /** Reference to orbit-relative frame. */ 45 private final OrbitRelativeFrame orbitRelativeFrame; 46 47 /** Reference to spacecraft body frame. */ 48 private final SpacecraftBodyFrame spacecraftBodyFrame; 49 50 /** Name of the frame. */ 51 private final String name; 52 53 /** 54 * Simple constructor. 55 * <p> 56 * At most one of {@code celestialBodyFrame}, {@code orbitRelativeFrame} or {@code spacecraftBodyFrame} may be non 57 * null. They may all be null if frame is unknown, in which case only the name will be available. 58 * </p> 59 * 60 * @param frame reference to node in Orekit frames tree (may be null) 61 * @param celestialBodyFrame reference to celestial body centered frame (may be null) 62 * @param orbitRelativeFrame reference to orbit-relative frame (may be null) 63 * @param spacecraftBodyFrame reference to spacecraft body frame (may be null) 64 * @param name name of the frame 65 */ 66 public FrameFacade(final Frame frame, 67 final CelestialBodyFrame celestialBodyFrame, 68 final OrbitRelativeFrame orbitRelativeFrame, 69 final SpacecraftBodyFrame spacecraftBodyFrame, 70 final String name) { 71 this.frame = frame; 72 this.celestialBodyFrame = celestialBodyFrame; 73 this.orbitRelativeFrame = orbitRelativeFrame; 74 this.spacecraftBodyFrame = spacecraftBodyFrame; 75 this.name = name; 76 } 77 78 /** 79 * Get the associated frame tree node. 80 * 81 * @return associated frame tree node, or null if none exists 82 */ 83 public Frame asFrame() { 84 return frame; 85 } 86 87 /** 88 * Get the associated {@link CelestialBodyFrame celestial body frame}. 89 * 90 * @return associated celestial body frame, or null if frame is associated to a 91 * {@link #asOrbitRelativeFrame() orbit}, a {@link #asSpacecraftBodyFrame spacecraft} or is not supported 92 */ 93 public CelestialBodyFrame asCelestialBodyFrame() { 94 return celestialBodyFrame; 95 } 96 97 /** 98 * Get the associated {@link OrbitRelativeFrame orbit relative frame}. 99 * 100 * @return associated orbit relative frame, or null if frame is associated to a 101 * {@link #asCelestialBodyFrame() celestial body}, a {@link #asSpacecraftBodyFrame spacecraft} or is not supported 102 */ 103 public OrbitRelativeFrame asOrbitRelativeFrame() { 104 return orbitRelativeFrame; 105 } 106 107 /** 108 * Get the associated {@link SpacecraftBodyFrame spacecraft body frame}. 109 * 110 * @return associated spacecraft body frame, or null if frame is associated to a 111 * {@link #asCelestialBodyFrame() celestial body}, an {@link #asOrbitRelativeFrame orbit} or is not supported 112 */ 113 public SpacecraftBodyFrame asSpacecraftBodyFrame() { 114 return spacecraftBodyFrame; 115 } 116 117 /** 118 * Get the CCSDS name for the frame. 119 * 120 * @return CCSDS name 121 */ 122 public String getName() { 123 return name; 124 } 125 126 /** 127 * Map an Orekit frame to a CCSDS frame facade. 128 * 129 * @param frame a reference frame. 130 * @return the CCSDS frame corresponding to the Orekit frame 131 */ 132 public static FrameFacade map(final Frame frame) { 133 final CelestialBodyFrame cbf = CelestialBodyFrame.map(frame); 134 return new FrameFacade(frame, cbf, null, null, cbf.getName()); 135 } 136 137 /** 138 * Simple constructor. 139 * 140 * @param name name of the frame 141 * @param conventions IERS conventions to use 142 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP 143 * @param dataContext to use when creating the frame 144 * @param allowCelestial if true, {@link CelestialBodyFrame} are allowed 145 * @param allowOrbit if true, {@link OrbitRelativeFrame} are allowed 146 * @param allowSpacecraft if true, {@link SpacecraftBodyFrame} are allowed 147 * @return frame facade corresponding to the CCSDS name 148 */ 149 public static FrameFacade parse(final String name, 150 final IERSConventions conventions, 151 final boolean simpleEOP, 152 final DataContext dataContext, 153 final boolean allowCelestial, 154 final boolean allowOrbit, 155 final boolean allowSpacecraft) { 156 try { 157 final CelestialBodyFrame cbf = CelestialBodyFrame.parse(name); 158 if (allowCelestial) { 159 return new FrameFacade(cbf.getFrame(conventions, simpleEOP, dataContext), 160 cbf, null, null, cbf.getName()); 161 } 162 } catch (IllegalArgumentException iaeC) { 163 try { 164 final OrbitRelativeFrame orf = OrbitRelativeFrame.valueOf(name.replace(' ', '_')); 165 if (allowOrbit) { 166 return new FrameFacade(null, null, orf, null, orf.name()); 167 } 168 } catch (IllegalArgumentException iaeO) { 169 try { 170 final SpacecraftBodyFrame sbf = SpacecraftBodyFrame.parse(name.replace(' ', '_')); 171 if (allowSpacecraft) { 172 return new FrameFacade(null, null, null, sbf, sbf.toString()); 173 } 174 } catch (OrekitException | IllegalArgumentException e) { 175 // nothing to do here, use fallback below 176 } 177 } 178 } 179 180 // we don't know any frame with this name, just store the name itself 181 return new FrameFacade(null, null, null, null, name); 182 183 } 184 185 /** 186 * Get the transform between {@link FrameFacade CCSDS frames}. 187 * <p> 188 * In case both input and output frames are {@link OrbitRelativeFrame orbit relative frame}, the returned transform 189 * will only be composed of a {@link Rotation rotation}. Only {@link LOFType commonly used orbit relative frames} 190 * will be recognized. 191 * <p> 192 * Note that if the input/output {@link FrameFacade CCSDS frame} is defined using a : 193 * <ul> 194 * <li><b>{@link CelestialBodyFrame celestial body frame}</b></li> 195 * <li><b>{@link SpacecraftBodyFrame spacecraft body frame}</b></li> 196 * </ul> 197 * then <b>an exception will be thrown</b> (currently not supported). 198 * <p> 199 * Note that the pivot frame provided <b>must be inertial</b> and <b>consistent</b> to what you are working with 200 * (i.e GCRF if around Earth for example). 201 * 202 * @param frameIn the input {@link FrameFacade CCSDS frame} to convert from 203 * @param frameOut the output {@link FrameFacade CCSDS frame} to convert to 204 * @param inertialPivotFrame <b>inertial</b> frame used as a pivot to create the transform 205 * @param date the date for the transform 206 * @param pv the position and velocity coordinates provider (required in case one of the frames is an 207 * {@link OrbitRelativeFrame orbit relative frame}) 208 * @return the transform between {@link FrameFacade CCSDS frames}. 209 */ 210 public static Transform getTransform(final FrameFacade frameIn, final FrameFacade frameOut, 211 final Frame inertialPivotFrame, 212 final AbsoluteDate date, final PVCoordinatesProvider pv) { 213 214 if (inertialPivotFrame.isPseudoInertial()) { 215 final Transform frameInToPivot = getTransformToPivot(frameIn, inertialPivotFrame, date, pv); 216 217 final Transform pivotToFrameOut = getTransformToPivot(frameOut, inertialPivotFrame, date, pv).getInverse(); 218 219 return new Transform(date, frameInToPivot, pivotToFrameOut); 220 } 221 else { 222 throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, inertialPivotFrame.getName()); 223 } 224 225 } 226 227 /** 228 * Get the transform between input {@link FrameFacade CCSDS frame} and an <b>inertial</b> 229 * {@link Frame Orekit frame}. 230 * 231 * @param frameIn the input {@link FrameFacade CCSDS frame} to convert from 232 * @param inertialPivotFrame <b>inertial</b> {@link Frame Orekit frame} to convert to 233 * @param date the date for the transform 234 * @param pv the position and velocity coordinates provider (required in case the input 235 * {@link FrameFacade CCSDS frame} is an {@link OrbitRelativeFrame orbit relative frame}) 236 * @return the transform between input {@link FrameFacade CCSDS frame} and an inertial {@link Frame Orekit frame} 237 */ 238 private static Transform getTransformToPivot(final FrameFacade frameIn, final Frame inertialPivotFrame, 239 final AbsoluteDate date, final PVCoordinatesProvider pv) { 240 final Transform frameInToPivot; 241 242 // Orekit frame 243 if (frameIn.asFrame() != null) { 244 frameInToPivot = frameIn.asFrame().getTransformTo(inertialPivotFrame, date); 245 } 246 247 // Local orbital frame 248 else if (frameIn.asOrbitRelativeFrame() != null) { 249 250 final LOFType lofIn = frameIn.asOrbitRelativeFrame().getLofType(); 251 252 if (lofIn != null) { 253 frameInToPivot = 254 lofIn.transformFromInertial(date, pv.getPVCoordinates(date, inertialPivotFrame)).getInverse(); 255 } 256 else { 257 throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.getName(), 258 inertialPivotFrame.getName()); 259 } 260 } 261 262 //Celestial body frame 263 else if (frameIn.asCelestialBodyFrame() != null) { 264 throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.asCelestialBodyFrame().getName(), 265 inertialPivotFrame.getName()); 266 } 267 268 // Spacecraft body frame 269 else { 270 throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.getName(), 271 inertialPivotFrame.getName()); 272 } 273 274 return frameInToPivot; 275 } 276 277 }