LofOffsetPointing.java

  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. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.hipparchus.RealFieldElement;
  21. import org.hipparchus.geometry.euclidean.threed.FieldLine;
  22. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  23. import org.hipparchus.geometry.euclidean.threed.Line;
  24. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  25. import org.orekit.bodies.BodyShape;
  26. import org.orekit.bodies.FieldGeodeticPoint;
  27. import org.orekit.bodies.GeodeticPoint;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.frames.FieldTransform;
  31. import org.orekit.frames.Frame;
  32. import org.orekit.frames.Transform;
  33. import org.orekit.time.AbsoluteDate;
  34. import org.orekit.time.FieldAbsoluteDate;
  35. import org.orekit.utils.CartesianDerivativesFilter;
  36. import org.orekit.utils.Constants;
  37. import org.orekit.utils.FieldPVCoordinatesProvider;
  38. import org.orekit.utils.PVCoordinatesProvider;
  39. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  40. import org.orekit.utils.TimeStampedPVCoordinates;


  41. /**
  42.  * This class provides a default attitude provider.

  43.  * <p>
  44.  * The attitude pointing law is defined by an attitude provider and
  45.  * the satellite axis vector chosen for pointing.
  46.  * <p>
  47.  * @author V&eacute;ronique Pommier-Maurussane
  48.  */
  49. public class LofOffsetPointing extends GroundPointing {

  50.     /** Serializable UID. */
  51.     private static final long serialVersionUID = 20150529L;

  52.     /** Rotation from local orbital frame. */
  53.     private final AttitudeProvider attitudeLaw;

  54.     /** Body shape. */
  55.     private final BodyShape shape;

  56.     /** Chosen satellite axis for pointing, given in satellite frame. */
  57.     private final Vector3D satPointingVector;

  58.     /** Creates new instance.
  59.      * @param inertialFrame frame in which orbital velocities are computed
  60.      * @param shape Body shape
  61.      * @param attLaw Attitude law
  62.      * @param satPointingVector satellite vector defining the pointing direction
  63.      * @exception OrekitException if the frame specified is not a pseudo-inertial frame
  64.      * @since 7.1
  65.      */
  66.     public LofOffsetPointing(final Frame inertialFrame, final BodyShape shape,
  67.                              final AttitudeProvider attLaw, final Vector3D satPointingVector)
  68.         throws OrekitException {
  69.         super(inertialFrame, shape.getBodyFrame());
  70.         this.shape = shape;
  71.         this.attitudeLaw = attLaw;
  72.         this.satPointingVector = satPointingVector;
  73.     }

  74.     /** {@inheritDoc} */
  75.     @Override
  76.     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
  77.                                 final AbsoluteDate date, final Frame frame)
  78.         throws OrekitException {
  79.         return attitudeLaw.getAttitude(pvProv, date, frame);
  80.     }

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     public <T extends RealFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
  84.                                                                         final FieldAbsoluteDate<T> date, final Frame frame)
  85.         throws OrekitException {
  86.         return attitudeLaw.getAttitude(pvProv, date, frame);
  87.     }

  88.     /** {@inheritDoc} */
  89.     public TimeStampedPVCoordinates getTargetPV(final PVCoordinatesProvider pvProv,
  90.                                                 final AbsoluteDate date, final Frame frame)
  91.         throws OrekitException {

  92.         // sample intersection points in current date neighborhood
  93.         final double h  = 0.1;
  94.         final List<TimeStampedPVCoordinates> sample = new ArrayList<>();
  95.         Transform centralRefToBody = null;
  96.         for (int i = -1; i < 2; ++i) {

  97.             final AbsoluteDate shifted = date.shiftedBy(i * h);

  98.             // transform from specified reference frame to spacecraft frame
  99.             final Transform refToSc =
  100.                             new Transform(shifted,
  101.                                           new Transform(shifted, pvProv.getPVCoordinates(shifted, frame).negate()),
  102.                                           new Transform(shifted, attitudeLaw.getAttitude(pvProv, shifted, frame).getOrientation()));

  103.             // transform from specified reference frame to body frame
  104.             final Transform refToBody = frame.getTransformTo(shape.getBodyFrame(), shifted);
  105.             if (i == 0) {
  106.                 centralRefToBody = refToBody;
  107.             }

  108.             sample.add(losIntersectionWithBody(new Transform(shifted, refToSc.getInverse(), refToBody)));

  109.         }

  110.         // use interpolation to compute properly the time-derivatives
  111.         final TimeStampedPVCoordinates targetBody =
  112.                 TimeStampedPVCoordinates.interpolate(date, CartesianDerivativesFilter.USE_P, sample);

  113.         // convert back to caller specified frame
  114.         return centralRefToBody.getInverse().transformPVCoordinates(targetBody);

  115.     }

  116.     /** {@inheritDoc} */
  117.     public <T extends RealFieldElement<T>> TimeStampedFieldPVCoordinates<T> getTargetPV(final FieldPVCoordinatesProvider<T> pvProv,
  118.                                                                                         final FieldAbsoluteDate<T> date,
  119.                                                                                         final Frame frame)
  120.         throws OrekitException {

  121.         // sample intersection points in current date neighborhood
  122.         final double h  = 0.1;
  123.         final List<TimeStampedFieldPVCoordinates<T>> sample = new ArrayList<>();
  124.         FieldTransform<T> centralRefToBody = null;
  125.         for (int i = -1; i < 2; ++i) {

  126.             final FieldAbsoluteDate<T> shifted = date.shiftedBy(i * h);

  127.             // transform from specified reference frame to spacecraft frame
  128.             final FieldTransform<T> refToSc =
  129.                             new FieldTransform<>(shifted,
  130.                                                  new FieldTransform<>(shifted, pvProv.getPVCoordinates(shifted, frame).negate()),
  131.                                                  new FieldTransform<>(shifted, attitudeLaw.getAttitude(pvProv, shifted, frame).getOrientation()));

  132.             // transform from specified reference frame to body frame
  133.             final FieldTransform<T> refToBody = frame.getTransformTo(shape.getBodyFrame(), shifted);
  134.             if (i == 0) {
  135.                 centralRefToBody = refToBody;
  136.             }

  137.             sample.add(losIntersectionWithBody(new FieldTransform<>(shifted, refToSc.getInverse(), refToBody)));

  138.         }

  139.         // use interpolation to compute properly the time-derivatives
  140.         final TimeStampedFieldPVCoordinates<T> targetBody =
  141.                         TimeStampedFieldPVCoordinates.interpolate(date, CartesianDerivativesFilter.USE_P, sample);

  142.         // convert back to caller specified frame
  143.         return centralRefToBody.getInverse().transformPVCoordinates(targetBody);

  144.     }

  145.     /** Compute line of sight intersection with body.
  146.      * @param scToBody transform from spacecraft frame to body frame
  147.      * @return intersection point in body frame (only the position is set!)
  148.      * @exception OrekitException if line of sight does not intersect body
  149.      */
  150.     private TimeStampedPVCoordinates losIntersectionWithBody(final Transform scToBody)
  151.         throws OrekitException {

  152.         // compute satellite pointing axis and position/velocity in body frame
  153.         final Vector3D pointingBodyFrame = scToBody.transformVector(satPointingVector);
  154.         final Vector3D pBodyFrame        = scToBody.transformPosition(Vector3D.ZERO);

  155.         // Line from satellite following pointing direction
  156.         // we use arbitrarily the Earth radius as a scaling factor, it could be anything else
  157.         final Line pointingLine = new Line(pBodyFrame,
  158.                                            pBodyFrame.add(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
  159.                                                           pointingBodyFrame),
  160.                                            1.0e-10);

  161.         // Intersection with body shape
  162.         final GeodeticPoint gpIntersection =
  163.             shape.getIntersectionPoint(pointingLine, pBodyFrame, shape.getBodyFrame(), scToBody.getDate());
  164.         final Vector3D pIntersection =
  165.             (gpIntersection == null) ? null : shape.transform(gpIntersection);

  166.         // Check there is an intersection and it is not in the reverse pointing direction
  167.         if ((pIntersection == null) ||
  168.             (Vector3D.dotProduct(pIntersection.subtract(pBodyFrame), pointingBodyFrame) < 0)) {
  169.             throw new OrekitException(OrekitMessages.ATTITUDE_POINTING_LAW_DOES_NOT_POINT_TO_GROUND);
  170.         }

  171.         return new TimeStampedPVCoordinates(scToBody.getDate(),
  172.                                             pIntersection, Vector3D.ZERO, Vector3D.ZERO);

  173.     }

  174.     /** Compute line of sight intersection with body.
  175.      * @param scToBody transform from spacecraft frame to body frame
  176.      * @param <T> type of the field elements
  177.      * @return intersection point in body frame (only the position is set!)
  178.      * @exception OrekitException if line of sight does not intersect body
  179.      */
  180.     private <T extends RealFieldElement<T>> TimeStampedFieldPVCoordinates<T> losIntersectionWithBody(final FieldTransform<T> scToBody)
  181.         throws OrekitException {

  182.         // compute satellite pointing axis and position/velocity in body frame
  183.         final FieldVector3D<T> pointingBodyFrame = scToBody.transformVector(satPointingVector);
  184.         final FieldVector3D<T> pBodyFrame        = scToBody.transformPosition(Vector3D.ZERO);

  185.         // Line from satellite following pointing direction
  186.         // we use arbitrarily the Earth radius as a scaling factor, it could be anything else
  187.         final FieldLine<T> pointingLine = new FieldLine<>(pBodyFrame,
  188.                                                           pBodyFrame.add(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
  189.                                                                          pointingBodyFrame),
  190.                                                           1.0e-10);

  191.         // Intersection with body shape
  192.         final FieldGeodeticPoint<T> gpIntersection =
  193.             shape.getIntersectionPoint(pointingLine, pBodyFrame, shape.getBodyFrame(), scToBody.getFieldDate());
  194.         final FieldVector3D<T> pIntersection =
  195.             (gpIntersection == null) ? null : shape.transform(gpIntersection);

  196.         // Check there is an intersection and it is not in the reverse pointing direction
  197.         if ((pIntersection == null) ||
  198.             (FieldVector3D.dotProduct(pIntersection.subtract(pBodyFrame), pointingBodyFrame).getReal() < 0)) {
  199.             throw new OrekitException(OrekitMessages.ATTITUDE_POINTING_LAW_DOES_NOT_POINT_TO_GROUND);
  200.         }

  201.         final FieldVector3D<T> zero = FieldVector3D.getZero(scToBody.getFieldDate().getField());
  202.         return new TimeStampedFieldPVCoordinates<>(scToBody.getDate(),
  203.                                                    pIntersection, zero, zero);

  204.     }

  205. }