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 }