1 /* Copyright 2002-2018 CS Systèmes d'Information 2 * Licensed to CS Systèmes d'Information (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.attitudes; 18 19 import org.hipparchus.RealFieldElement; 20 import org.hipparchus.geometry.euclidean.threed.FieldRotation; 21 import org.hipparchus.geometry.euclidean.threed.Rotation; 22 import org.hipparchus.geometry.euclidean.threed.RotationConvention; 23 import org.hipparchus.geometry.euclidean.threed.RotationOrder; 24 import org.orekit.errors.OrekitException; 25 import org.orekit.errors.OrekitMessages; 26 import org.orekit.frames.FieldTransform; 27 import org.orekit.frames.Frame; 28 import org.orekit.frames.LOFType; 29 import org.orekit.frames.Transform; 30 import org.orekit.time.AbsoluteDate; 31 import org.orekit.time.FieldAbsoluteDate; 32 import org.orekit.utils.FieldPVCoordinates; 33 import org.orekit.utils.FieldPVCoordinatesProvider; 34 import org.orekit.utils.PVCoordinates; 35 import org.orekit.utils.PVCoordinatesProvider; 36 37 38 /** 39 * Attitude law defined by fixed Roll, Pitch and Yaw angles (in any order) 40 * with respect to a local orbital frame. 41 42 * <p> 43 * The attitude provider is defined as a rotation offset from some local orbital frame. 44 * @author Véronique Pommier-Maurussane 45 */ 46 public class LofOffset implements AttitudeProvider { 47 48 /** Serializable UID. */ 49 private static final long serialVersionUID = -713570668596014285L; 50 51 /** Type of Local Orbital Frame. */ 52 private LOFType type; 53 54 /** Rotation from local orbital frame. */ 55 private final Rotation offset; 56 57 /** Inertial frame with respect to which orbit should be computed. */ 58 private final Frame inertialFrame; 59 60 /** Create a LOF-aligned attitude. 61 * <p> 62 * Calling this constructor is equivalent to call 63 * {@code LofOffset(inertialFrame, LOFType, RotationOrder.XYZ, 0, 0, 0)} 64 * </p> 65 * @param inertialFrame inertial frame with respect to which orbit should be computed 66 * @param type type of Local Orbital Frame 67 * @exception OrekitException if inertialFrame is not a pseudo-inertial frame 68 */ 69 public LofOffset(final Frame inertialFrame, final LOFType type) throws OrekitException { 70 this(inertialFrame, type, RotationOrder.XYZ, 0, 0, 0); 71 } 72 73 /** Creates new instance. 74 * <p> 75 * An important thing to note is that the rotation order and angles signs used here 76 * are compliant with an <em>attitude</em> definition, i.e. they correspond to 77 * a frame that rotate in a field of fixed vectors. So to retrieve the angles 78 * provided here from the Hipparchus underlying rotation, one has to either use the 79 * {@link RotationConvention#VECTOR_OPERATOR} and <em>revert</em> the rotation, or 80 * to use {@link RotationConvention#FRAME_TRANSFORM} as in the following code snippet: 81 * </p> 82 * <pre> 83 * LofOffset law = new LofOffset(inertial, lofType, order, alpha1, alpha2, alpha3); 84 * Rotation offsetAtt = law.getAttitude(orbit).getRotation(); 85 * Rotation alignedAtt = new LofOffset(inertial, lofType).getAttitude(orbit).getRotation(); 86 * Rotation offsetProper = offsetAtt.compose(alignedAtt.revert(), RotationConvention.VECTOR_OPERATOR); 87 * 88 * // note the call to revert and the conventions in the following statement 89 * double[] anglesV = offsetProper.revert().getAngles(order, RotationConvention.VECTOR_OPERATOR); 90 * System.out.println(alpha1 + " == " + anglesV[0]); 91 * System.out.println(alpha2 + " == " + anglesV[1]); 92 * System.out.println(alpha3 + " == " + anglesV[2]); 93 * 94 * // note the conventions in the following statement 95 * double[] anglesF = offsetProper.getAngles(order, RotationConvention.FRAME_TRANSFORM); 96 * System.out.println(alpha1 + " == " + anglesF[0]); 97 * System.out.println(alpha2 + " == " + anglesF[1]); 98 * System.out.println(alpha3 + " == " + anglesF[2]); 99 * </pre> 100 * @param inertialFrame inertial frame with respect to which orbit should be computed 101 * @param type type of Local Orbital Frame 102 * @param order order of rotations to use for (alpha1, alpha2, alpha3) composition 103 * @param alpha1 angle of the first elementary rotation 104 * @param alpha2 angle of the second elementary rotation 105 * @param alpha3 angle of the third elementary rotation 106 * @exception OrekitException if inertialFrame is not a pseudo-inertial frame 107 */ 108 public LofOffset(final Frame inertialFrame, final LOFType type, 109 final RotationOrder order, final double alpha1, 110 final double alpha2, final double alpha3) throws OrekitException { 111 this.type = type; 112 this.offset = new Rotation(order, RotationConvention.VECTOR_OPERATOR, alpha1, alpha2, alpha3).revert(); 113 if (!inertialFrame.isPseudoInertial()) { 114 throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, 115 inertialFrame.getName()); 116 } 117 this.inertialFrame = inertialFrame; 118 } 119 120 121 /** {@inheritDoc} */ 122 public Attitude getAttitude(final PVCoordinatesProvider pvProv, 123 final AbsoluteDate date, final Frame frame) 124 throws OrekitException { 125 126 // construction of the local orbital frame, using PV from inertial frame 127 final PVCoordinates pv = pvProv.getPVCoordinates(date, inertialFrame); 128 final Transform inertialToLof = type.transformFromInertial(date, pv); 129 130 // take into account the specified start frame (which may not be an inertial one) 131 final Transform frameToInertial = frame.getTransformTo(inertialFrame, date); 132 final Transform frameToLof = new Transform(date, frameToInertial, inertialToLof); 133 134 // compose with offset rotation 135 return new Attitude(date, frame, 136 offset.compose(frameToLof.getRotation(), RotationConvention.VECTOR_OPERATOR), 137 offset.applyTo(frameToLof.getRotationRate()), 138 offset.applyTo(frameToLof.getRotationAcceleration())); 139 140 } 141 142 /** {@inheritDoc} */ 143 public <T extends RealFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv, 144 final FieldAbsoluteDate<T> date, 145 final Frame frame) 146 throws OrekitException { 147 148 // construction of the local orbital frame, using PV from inertial frame 149 final FieldPVCoordinates<T> pv = pvProv.getPVCoordinates(date, inertialFrame); 150 final FieldTransform<T> inertialToLof = type.transformFromInertial(date, pv); 151 152 // take into account the specified start frame (which may not be an inertial one) 153 final FieldTransform<T> frameToInertial = frame.getTransformTo(inertialFrame, date); 154 final FieldTransform<T> frameToLof = new FieldTransform<>(date, frameToInertial, inertialToLof); 155 156 // compose with offset rotation 157 return new FieldAttitude<>(date, frame, 158 frameToLof.getRotation().compose(offset, RotationConvention.FRAME_TRANSFORM), 159 FieldRotation.applyTo(offset, frameToLof.getRotationRate()), 160 FieldRotation.applyTo(offset, frameToLof.getRotationAcceleration())); 161 162 } 163 }