1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.attitudes;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.geometry.euclidean.threed.FieldLine;
24 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
25 import org.hipparchus.geometry.euclidean.threed.Line;
26 import org.hipparchus.geometry.euclidean.threed.Vector3D;
27 import org.hipparchus.geometry.euclidean.threed.Rotation;
28 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
29 import org.orekit.bodies.BodyShape;
30 import org.orekit.bodies.FieldGeodeticPoint;
31 import org.orekit.bodies.GeodeticPoint;
32 import org.orekit.errors.OrekitException;
33 import org.orekit.errors.OrekitMessages;
34 import org.orekit.frames.FieldStaticTransform;
35 import org.orekit.frames.FieldTransform;
36 import org.orekit.frames.Frame;
37 import org.orekit.frames.StaticTransform;
38 import org.orekit.frames.Transform;
39 import org.orekit.time.AbsoluteDate;
40 import org.orekit.time.FieldAbsoluteDate;
41 import org.orekit.time.FieldTimeInterpolator;
42 import org.orekit.time.TimeInterpolator;
43 import org.orekit.utils.CartesianDerivativesFilter;
44 import org.orekit.utils.Constants;
45 import org.orekit.utils.FieldPVCoordinatesProvider;
46 import org.orekit.utils.PVCoordinatesProvider;
47 import org.orekit.utils.TimeStampedFieldPVCoordinates;
48 import org.orekit.utils.TimeStampedFieldPVCoordinatesHermiteInterpolator;
49 import org.orekit.utils.TimeStampedPVCoordinates;
50 import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator;
51
52
53
54
55
56
57
58
59
60
61 public class LofOffsetPointing extends GroundPointing {
62
63
64 private final AttitudeProvider attitudeLaw;
65
66
67 private final BodyShape shape;
68
69
70 private final Vector3D satPointingVector;
71
72
73
74
75
76
77
78
79 public LofOffsetPointing(final Frame inertialFrame, final BodyShape shape,
80 final AttitudeProvider attLaw, final Vector3D satPointingVector) {
81 super(inertialFrame, shape.getBodyFrame());
82 this.shape = shape;
83 this.attitudeLaw = attLaw;
84 this.satPointingVector = satPointingVector;
85 }
86
87
88 @Override
89 public Attitude getAttitude(final PVCoordinatesProvider pvProv,
90 final AbsoluteDate date, final Frame frame) {
91 return attitudeLaw.getAttitude(pvProv, date, frame);
92 }
93
94
95 @Override
96 public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
97 final FieldAbsoluteDate<T> date, final Frame frame) {
98 return attitudeLaw.getAttitude(pvProv, date, frame);
99 }
100
101
102 @Override
103 public Rotation getAttitudeRotation(final PVCoordinatesProvider pvProv,
104 final AbsoluteDate date, final Frame frame) {
105 return attitudeLaw.getAttitudeRotation(pvProv, date, frame);
106 }
107
108
109 @Override
110 public <T extends CalculusFieldElement<T>> FieldRotation<T> getAttitudeRotation(final FieldPVCoordinatesProvider<T> pvProv,
111 final FieldAbsoluteDate<T> date, final Frame frame) {
112 return attitudeLaw.getAttitudeRotation(pvProv, date, frame);
113 }
114
115
116 @Override
117 public TimeStampedPVCoordinates getTargetPV(final PVCoordinatesProvider pvProv,
118 final AbsoluteDate date, final Frame frame) {
119
120
121 final double h = 0.1;
122 final List<TimeStampedPVCoordinates> sample = new ArrayList<>();
123 Transform centralRefToBody = null;
124 for (int i = -1; i < 2; ++i) {
125
126 final AbsoluteDate shifted = date.shiftedBy(i * h);
127
128
129 final StaticTransform refToSc = StaticTransform.of(shifted, pvProv.getPosition(shifted, frame).negate(),
130 attitudeLaw.getAttitudeRotation(pvProv, shifted, frame));
131
132
133 final StaticTransform refToBody;
134 if (i == 0) {
135 refToBody = centralRefToBody = frame.getTransformTo(shape.getBodyFrame(), shifted);
136 } else {
137 refToBody = frame.getStaticTransformTo(shape.getBodyFrame(), shifted);
138 }
139
140 sample.add(losIntersectionWithBody(StaticTransform.compose(shifted, refToSc.getInverse(), refToBody)));
141
142 }
143
144
145 final TimeInterpolator<TimeStampedPVCoordinates> interpolator =
146 new TimeStampedPVCoordinatesHermiteInterpolator(sample.size(), CartesianDerivativesFilter.USE_P);
147
148
149 final TimeStampedPVCoordinates targetBody =
150 interpolator.interpolate(date, sample);
151
152
153 return centralRefToBody.getInverse().transformPVCoordinates(targetBody);
154
155 }
156
157
158 @Override
159 protected Vector3D getTargetPosition(final PVCoordinatesProvider pvProv, final AbsoluteDate date, final Frame frame) {
160
161
162 final StaticTransform refToSc = StaticTransform.of(date, pvProv.getPosition(date, frame).negate(),
163 attitudeLaw.getAttitudeRotation(pvProv, date, frame));
164
165
166 final StaticTransform refToBody = frame.getStaticTransformTo(shape.getBodyFrame(), date);
167 final Vector3D targetBody = losIntersectionWithBody(StaticTransform.compose(date, refToSc.getInverse(), refToBody)).getPosition();
168
169
170 return refToBody.getInverse().transformPosition(targetBody);
171 }
172
173
174 @Override
175 public <T extends CalculusFieldElement<T>> TimeStampedFieldPVCoordinates<T> getTargetPV(final FieldPVCoordinatesProvider<T> pvProv,
176 final FieldAbsoluteDate<T> date,
177 final Frame frame) {
178
179
180 final double h = 0.1;
181 final List<TimeStampedFieldPVCoordinates<T>> sample = new ArrayList<>();
182 FieldTransform<T> centralRefToBody = null;
183 for (int i = -1; i < 2; ++i) {
184
185 final FieldAbsoluteDate<T> shifted = date.shiftedBy(i * h);
186
187
188 final FieldStaticTransform<T> refToSc = FieldStaticTransform.of(shifted,
189 pvProv.getPVCoordinates(shifted, frame).getPosition().negate(), attitudeLaw.getAttitudeRotation(pvProv, shifted, frame));
190
191
192 final FieldStaticTransform<T> refToBody;
193 if (i == 0) {
194 refToBody = centralRefToBody = frame.getTransformTo(shape.getBodyFrame(), shifted);
195 } else {
196 refToBody = frame.getStaticTransformTo(shape.getBodyFrame(), shifted);
197 }
198
199 sample.add(losIntersectionWithBody(FieldStaticTransform.compose(shifted, refToSc.getInverse(), refToBody)));
200
201 }
202
203
204 final FieldTimeInterpolator<TimeStampedFieldPVCoordinates<T>, T> interpolator =
205 new TimeStampedFieldPVCoordinatesHermiteInterpolator<>(sample.size(), CartesianDerivativesFilter.USE_P);
206
207
208 final TimeStampedFieldPVCoordinates<T> targetBody =
209 interpolator.interpolate(date, sample);
210
211
212 return centralRefToBody.getInverse().transformPVCoordinates(targetBody);
213
214 }
215
216
217 @Override
218 protected <T extends CalculusFieldElement<T>> FieldVector3D<T> getTargetPosition(final FieldPVCoordinatesProvider<T> pvProv,
219 final FieldAbsoluteDate<T> date,
220 final Frame frame) {
221
222
223 final FieldStaticTransform<T> refToSc = FieldStaticTransform.of(date, pvProv.getPosition(date, frame).negate(),
224 attitudeLaw.getAttitudeRotation(pvProv, date, frame));
225
226
227 final FieldStaticTransform<T> refToBody = frame.getStaticTransformTo(shape.getBodyFrame(), date);
228 final FieldVector3D<T> targetBody = losIntersectionWithBody(FieldStaticTransform.compose(date, refToSc.getInverse(), refToBody)).getPosition();
229
230
231 return refToBody.getInverse().transformPosition(targetBody);
232 }
233
234
235
236
237
238 private TimeStampedPVCoordinates losIntersectionWithBody(final StaticTransform scToBody) {
239
240
241 final Vector3D pointingBodyFrame = scToBody.transformVector(satPointingVector);
242 final Vector3D pBodyFrame = scToBody.transformPosition(Vector3D.ZERO);
243
244
245
246 final Line pointingLine = new Line(pBodyFrame,
247 pBodyFrame.add(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
248 pointingBodyFrame),
249 1.0e-10);
250
251
252 final GeodeticPoint gpIntersection =
253 shape.getIntersectionPoint(pointingLine, pBodyFrame, shape.getBodyFrame(), scToBody.getDate());
254 final Vector3D pIntersection =
255 (gpIntersection == null) ? null : shape.transform(gpIntersection);
256
257
258 if (pIntersection == null ||
259 Vector3D.dotProduct(pIntersection.subtract(pBodyFrame), pointingBodyFrame) < 0) {
260 throw new OrekitException(OrekitMessages.ATTITUDE_POINTING_LAW_DOES_NOT_POINT_TO_GROUND);
261 }
262
263 return new TimeStampedPVCoordinates(scToBody.getDate(),
264 pIntersection, Vector3D.ZERO, Vector3D.ZERO);
265
266 }
267
268
269
270
271
272
273 private <T extends CalculusFieldElement<T>> TimeStampedFieldPVCoordinates<T> losIntersectionWithBody(final FieldStaticTransform<T> scToBody) {
274
275
276 final FieldVector3D<T> pointingBodyFrame = scToBody.transformVector(satPointingVector);
277 final FieldVector3D<T> pBodyFrame = scToBody.transformPosition(Vector3D.ZERO);
278
279
280
281 final FieldLine<T> pointingLine = new FieldLine<>(pBodyFrame,
282 pBodyFrame.add(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
283 pointingBodyFrame),
284 1.0e-10);
285
286
287 final FieldGeodeticPoint<T> gpIntersection =
288 shape.getIntersectionPoint(pointingLine, pBodyFrame, shape.getBodyFrame(), new FieldAbsoluteDate<>(pBodyFrame.getX().getField(), scToBody.getDate()));
289 final FieldVector3D<T> pIntersection =
290 (gpIntersection == null) ? null : shape.transform(gpIntersection);
291
292
293 if (pIntersection == null ||
294 FieldVector3D.dotProduct(pIntersection.subtract(pBodyFrame), pointingBodyFrame).getReal() < 0) {
295 throw new OrekitException(OrekitMessages.ATTITUDE_POINTING_LAW_DOES_NOT_POINT_TO_GROUND);
296 }
297
298 final FieldVector3D<T> zero = FieldVector3D.getZero(pBodyFrame.getX().getField());
299 return new TimeStampedFieldPVCoordinates<>(scToBody.getDate(),
300 pIntersection, zero, zero);
301
302 }
303
304 }