1   /* Copyright 2002-2025 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.frames.encounter;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
22  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
23  import org.hipparchus.geometry.euclidean.threed.Rotation;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.hipparchus.geometry.euclidean.twod.FieldVector2D;
26  import org.hipparchus.geometry.euclidean.twod.Vector2D;
27  import org.hipparchus.linear.Array2DRowFieldMatrix;
28  import org.hipparchus.linear.Array2DRowRealMatrix;
29  import org.hipparchus.linear.FieldMatrix;
30  import org.hipparchus.linear.MatrixUtils;
31  import org.hipparchus.linear.RealMatrix;
32  import org.hipparchus.util.MathArrays;
33  import org.orekit.frames.LOF;
34  import org.orekit.time.AbsoluteDate;
35  import org.orekit.time.FieldAbsoluteDate;
36  import org.orekit.utils.FieldPVCoordinates;
37  import org.orekit.utils.PVCoordinates;
38  
39  import java.util.Arrays;
40  import java.util.List;
41  import java.util.stream.Collectors;
42  
43  /**
44   * Interface for encounter local orbital frame.
45   * <p>
46   * Encounter local orbital frame are defined using two objects, one of them is placed at the origin and the other is
47   * expressed relatively to the origin.
48   *
49   * @author Vincent Cucchietti
50   * @since 12.0
51   */
52  public interface EncounterLOF extends LOF {
53  
54      /**
55       * {@inheritDoc} It is unnecessary to use this method when dealing with {@link EncounterLOF}, use
56       * {@link #rotationFromInertial(Field, FieldPVCoordinates)} instead.
57       */
58      @Override
59      default <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(Field<T> field,
60                                                                                        FieldAbsoluteDate<T> date,
61                                                                                        FieldPVCoordinates<T> pv) {
62          return rotationFromInertial(field, pv);
63      }
64  
65      /**
66       * {@inheritDoc} It is unnecessary to use this method when dealing with {@link EncounterLOF}, use
67       * {@link #rotationFromInertial(PVCoordinates)} instead.
68       */
69      @Override
70      default Rotation rotationFromInertial(AbsoluteDate date, PVCoordinates pv) {
71          return rotationFromInertial(pv);
72      }
73  
74      /**
75       * Get the rotation from inertial to this encounter local orbital frame.
76       * <p>
77       * <b>BEWARE: The given origin's position and velocity coordinates must be given in the frame in which this instance
78       * has been expressed in.</b>
79       *
80       * @param field field to which the elements belong
81       * @param origin position-velocity of the origin in the same inertial frame as the one this instance has been expressed
82       * in.
83       * @param <T> type of the field elements
84       *
85       * @return rotation from inertial to this encounter local orbital frame
86       */
87      default <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
88                                                                                        final FieldPVCoordinates<T> origin) {
89          return rotationFromInertial(field, origin, getFieldOther(field));
90      }
91  
92      /**
93       * Get the rotation from inertial to this encounter local orbital frame.
94       * <p>
95       * <b>BEWARE: The given origin's position and velocity coordinates must be given in the frame in which this instance
96       * has been expressed in.</b>
97       *
98       * @param origin position-velocity of the origin in some inertial frame
99       *
100      * @return rotation from inertial to this encounter local orbital frame
101      */
102     default Rotation rotationFromInertial(final PVCoordinates origin) {
103         return rotationFromInertial(origin, getOther());
104     }
105 
106     /**
107      * Get the rotation from inertial to this encounter local orbital frame.
108      * <p>
109      * <b>BEWARE: The given origin's position and velocity coordinates must be given in the frame in which this instance
110      * has been expressed in.</b>
111      *
112      * @param field field to which the elements belong
113      * @param origin position-velocity of the origin in the same inertial frame as other
114      * @param other position-velocity of the other in the same inertial frame as origin
115      * @param <T> type of the field elements
116      *
117      * @return rotation from inertial to this encounter local orbital frame
118      */
119     <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(Field<T> field,
120                                                                               FieldPVCoordinates<T> origin,
121                                                                               FieldPVCoordinates<T> other);
122 
123     /**
124      * Get the rotation from inertial to this encounter local orbital frame.
125      * <p>
126      * <b>BEWARE: The given origin's position and velocity coordinates must be given in the frame in which this instance
127      * has been expressed in.</b>
128      *
129      * @param origin position-velocity of the origin in the same inertial frame as other
130      * @param other position-velocity of the other instance in the same inertial frame as origin
131      *
132      * @return rotation from inertial to this encounter local orbital frame
133      */
134     Rotation rotationFromInertial(PVCoordinates origin, PVCoordinates other);
135 
136     /**
137      * Project given {@link RealMatrix matrix} expressed in this encounter local orbital frame onto the collision plane.
138      *
139      * @param matrix matrix to project, a 3 by 3 matrix is expected
140      *
141      * @return projected matrix onto the collision plane defined by this encounter local orbital frame
142      */
143     default RealMatrix projectOntoCollisionPlane(RealMatrix matrix) {
144         final RealMatrix projectionMatrix = computeProjectionMatrix();
145         return projectionMatrix.multiply(matrix.multiplyTransposed(projectionMatrix));
146     }
147 
148     /**
149      * Get the 2x3 projection matrix that projects values expressed in this encounter local orbital frame to the collision
150      * plane.
151      *
152      * @return 2x3 projection matrix
153      */
154     default RealMatrix computeProjectionMatrix() {
155         // Remove axis normal to collision plane from the identity matrix
156         final RealMatrix identity = MatrixUtils.createRealIdentityMatrix(3);
157         final List<double[]> projectionMatrixDataList = Arrays.stream(identity.getData())
158                                                               .filter(values -> !Arrays.equals(values,
159                                                                                                getAxisNormalToCollisionPlane().toArray()))
160                                                               .collect(Collectors.toList());
161 
162         // Map list<double[]> to double[][]
163         final double[][] projectionMatrixData = new double[2][3];
164         for (int i = 0; i < 2; i++) {
165             projectionMatrixData[i] = projectionMatrixDataList.get(i);
166         }
167 
168         return new Array2DRowRealMatrix(projectionMatrixData);
169     }
170 
171     /**
172      * Project given {@link RealMatrix matrix} expressed in this encounter local orbital frame onto the collision plane
173      * defined by this same encounter local orbital frame.
174      *
175      * @param matrix matrix to project, a 3 by 3 matrix is expected
176      * @param <T> type of the field elements
177      *
178      * @return projected matrix onto the collision plane defined by this encounter local orbital frame
179      */
180     default <T extends CalculusFieldElement<T>> FieldMatrix<T> projectOntoCollisionPlane(FieldMatrix<T> matrix) {
181         final FieldMatrix<T> projectionMatrix = computeProjectionMatrix(matrix.getField());
182         return projectionMatrix.multiply(matrix.multiplyTransposed(projectionMatrix));
183     }
184 
185     /**
186      * Get the 2x3 projection matrix that projects values expressed in this encounter local orbital frame to the collision
187      * plane defined by this same encounter local orbital frame.
188      *
189      * @param field field to which the elements belong
190      * @param <T> type of the field elements
191      *
192      * @return 2x3 projection matrix
193      */
194     default <T extends CalculusFieldElement<T>> FieldMatrix<T> computeProjectionMatrix(Field<T> field) {
195         // Remove axis normal to collision plane from the identity matrix
196         final FieldMatrix<T> identity = MatrixUtils.createFieldIdentityMatrix(field, 3);
197         final List<T[]> projectionMatrixDataList = Arrays.stream(identity.getData())
198                                                          .filter(values -> !Arrays.equals(values,
199                                                                                           getAxisNormalToCollisionPlane(
200                                                                                                   field).toArray()))
201                                                          .collect(Collectors.toList());
202 
203         // Map list<C[]> to C[][]
204         final T[][] projectionMatrixData = MathArrays.buildArray(field, 2, 3);
205         for (int i = 0; i < 2; i++) {
206             projectionMatrixData[i] = projectionMatrixDataList.get(i);
207         }
208 
209         return new Array2DRowFieldMatrix<>(projectionMatrixData);
210     }
211 
212     /**
213      * Get the axis normal to the collision plane (i, j or k) in this encounter local orbital frame.
214      *
215      * @param field field of the elements
216      * @param <T> type of the field elements
217      *
218      * @return axis normal to the collision plane (i, j or k) in this encounter local orbital frame
219      */
220     <T extends CalculusFieldElement<T>> FieldVector3D<T> getAxisNormalToCollisionPlane(Field<T> field);
221 
222     /**
223      * Project given {@link Vector3D vector} expressed in this encounter local orbital frame onto the collision plane.
224      *
225      * @param vector vector to project
226      *
227      * @return projected vector onto the collision plane defined by this encounter local orbital frame
228      */
229     default Vector2D projectOntoCollisionPlane(Vector3D vector) {
230         final RealMatrix projectionMatrix = computeProjectionMatrix();
231         final RealMatrix vectorInMatrix   = new Array2DRowRealMatrix(vector.toArray());
232 
233         return new Vector2D(projectionMatrix.multiply(vectorInMatrix).getColumn(0));
234     }
235 
236     /**
237      * Project given {@link Vector3D vector} expressed in this encounter local orbital frame onto the collision plane.
238      *
239      * @param vector vector to project
240      * @param <T> type of the field elements
241      *
242      * @return projected vector onto the collision plane defined by this encounter local orbital frame
243      */
244     default <T extends CalculusFieldElement<T>> FieldVector2D<T> projectOntoCollisionPlane(
245             final FieldVector3D<T> vector) {
246         final FieldMatrix<T> projectionMatrix = computeProjectionMatrix(vector.getX().getField());
247         final FieldMatrix<T> vectorInMatrix   = new Array2DRowFieldMatrix<>(vector.toArray());
248 
249         return new FieldVector2D<>(projectionMatrix.multiply(vectorInMatrix).getColumn(0));
250     }
251 
252     /** Get other's position and velocity coordinates.
253      * @param field field of the element
254      * @param <T> type of the element
255      *
256      * @return other's position and velocity coordinates
257      */
258     <T extends CalculusFieldElement<T>> FieldPVCoordinates<T> getFieldOther(Field<T> field);
259 
260     /**
261      * Get the axis normal to the collision plane (i, j or k) in this encounter local orbital frame.
262      *
263      * @return axis normal to the collision plane (i, j or k) in this encounter local orbital frame
264      */
265     Vector3D getAxisNormalToCollisionPlane();
266 
267     /** Get other's position and velocity coordinates.
268      * @return other's position and velocity coordinates
269      */
270     PVCoordinates getOther();
271 
272     /** Get flag that indicates if current local orbital frame shall be treated as pseudo-inertial.
273      * @return flag that indicates if current local orbital frame shall be treated as pseudo-inertial
274      */
275     @Override
276     default boolean isQuasiInertial() {
277         return true;
278     }
279 
280 }