1   /* Copyright 2022-2025 Luc Maisonobe
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.forces;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.hipparchus.util.FastMath;
23  import org.hipparchus.util.FieldSinCos;
24  import org.hipparchus.util.SinCos;
25  import org.orekit.propagation.FieldSpacecraftState;
26  import org.orekit.propagation.SpacecraftState;
27  import org.orekit.time.AbsoluteDate;
28  
29  /** Class representing one panel of a satellite, slewing about an axis at constant rate.
30   * <p>
31   * It is mainly used to represent a solar array with fixed rate rotation.
32   * </p>
33   * <p>
34   * The panel rotation evolves linearly according to a start position and an
35   * angular rate (which can be set to 0 for non-rotating panels, which may
36   * occur in special modes or during contingencies).
37   * </p>
38   * <p>
39   * These panels are considered to be always {@link #isDoubleSided() double-sided}.
40   * </p>
41   *
42   * @author Luc Maisonobe
43   * @since 3.0
44   */
45  public class SlewingPanel extends Panel {
46  
47      /** Rotation rate of the panel (rad/s). */
48      private final double rotationRate;
49  
50      /** Reference date for the panel rotation. */
51      private final AbsoluteDate referenceDate;
52  
53      /** Panel reference axis in spacecraft frame (may be null). */
54      private final Vector3D rX;
55  
56      /** Panel third axis in spacecraft frame (may be null). */
57      private final Vector3D rY;
58  
59      /** Simple constructor.
60       * <p>
61       * As the sum of absorption coefficient, specular reflection coefficient and
62       * diffuse reflection coefficient is exactly 1, only the first two coefficients
63       * are needed here, the third one is deduced from the other ones.
64       * </p>
65       * <p>
66       * The panel is considered to rotate about one axis in order to make its normal
67       * point as close as possible to the target. It means the target will always be
68       * in the plane defined by the rotation axis and the panel normal.
69       * </p>
70       * @param rotationAxis rotation axis of the panel
71       * @param rotationRate rotation rate of the panel (rad/s)
72       * @param referenceDate reference date for the panel rotation
73       * @param referenceNormal direction of the panel normal at reference date in spacecraft frame
74       * @param area panel area in m²
75       * @param drag drag coefficient
76       * @param liftRatio drag lift ratio (proportion between 0 and 1 of atmosphere modecules
77       * that will experience specular reflection when hitting spacecraft instead
78       * of experiencing diffuse reflection, hence producing lift)
79       * @param absorption radiation pressure absorption coefficient (between 0 and 1)
80       * @param reflection radiation pressure specular reflection coefficient (between 0 and 1)
81       */
82      public SlewingPanel(final Vector3D rotationAxis, final double rotationRate,
83                          final AbsoluteDate referenceDate, final Vector3D referenceNormal,
84                          final double area,
85                          final double drag, final double liftRatio,
86                          final double absorption, final double reflection) {
87          super(area, true, drag, liftRatio, absorption, reflection);
88  
89          this.rotationRate    = rotationRate;
90          this.referenceDate   = referenceDate;
91          this.rY              = Vector3D.crossProduct(rotationAxis, referenceNormal).normalize();
92          this.rX              = Vector3D.crossProduct(rY, rotationAxis).normalize();
93  
94      }
95  
96      /** {@inheritDoc} */
97      @Override
98      public Vector3D getNormal(final SpacecraftState state) {
99          // use a simple rotation at fixed rate
100         final SinCos sc = FastMath.sinCos(state.getDate().durationFrom(referenceDate) * rotationRate);
101         return new Vector3D(sc.cos(), rX, sc.sin(), rY);
102     }
103 
104     /** {@inheritDoc} */
105     @Override
106     public <T extends CalculusFieldElement<T>> FieldVector3D<T> getNormal(final FieldSpacecraftState<T> state) {
107         // use a simple rotation at fixed rate
108         final FieldSinCos<T> sc = FastMath.sinCos(state.getDate().durationFrom(referenceDate).multiply(rotationRate));
109         return new FieldVector3D<>(sc.cos(), rX, sc.sin(), rY);
110     }
111 
112 }