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.data;
18
19 import org.orekit.errors.OrekitInternalError;
20
21 /** Encoder/decoder for Delaunay and planetary multipliers keys.
22 * <p>
23 * As Delaunay and planetary multipliers often have a lot of zeroes
24 * and the non-zero multipliers are in a small range, it makes sense
25 * to encode them in a compact representation that can be used as
26 * a key in hash tables. This class does the encoding/decoding of
27 * such keys.
28 * </p>
29 * <p>
30 * The encoding scheme is as follows, numbering bits from
31 * 0 for least significant bit to 63 for most significant bit:
32 * </p>
33 * <ul>
34 * <li>bits 0 to 14: mask for the 15 coefficients</li>
35 * <li>bits 15 to 63: split into 7 slots each 7 bits long and
36 * each encoding a coefficient ci + 64, where ci is the i-th
37 * non-zero coefficient</li>
38 * </ul>
39 * <p>
40 * This scheme allows to encode 7 non-zero integers between -64 to +63 among 15.
41 * As the current Poisson series used in Orekit have at most 6 non-zero coefficients
42 * and all the coefficients are between -21 and +20, we have some extension margin.
43 * </p>
44 */
45 class NutationCodec {
46
47 /** Current multiplier flag bit. */
48 private long flag;
49
50 /** Current coefficient shift. */
51 private int shift;
52
53 /** Current key value. */
54 private long key;
55
56 /** Simple constructor.
57 * @param key key
58 */
59 private NutationCodec(final long key) {
60 flag = 0x1l;
61 shift = 15;
62 this.key = key;
63 }
64
65 /** Get the key value.
66 * @return key value
67 */
68 public long getKey() {
69 return key;
70 }
71
72 /** Encode one more multiplier in the key.
73 * @param multiplier multiplier to encode
74 */
75 private void addMultiplier(final int multiplier) {
76
77 if (multiplier != 0) {
78 // this is a coefficient we want to store
79 key = key | flag;
80 if (shift > 57 || multiplier < -64 || multiplier > 63) {
81 // this should never happen, we exceed the encoding capacity
82 throw new OrekitInternalError(null);
83 }
84 key = key | (((multiplier + 64l) & 0x7Fl) << shift);
85 shift += 7;
86 }
87
88 // update bit mask
89 flag = flag << 1;
90
91 }
92
93 /** Decode one multiplier from the key.
94 * @return decoded multiplier
95 */
96 private int nextMultiplier() {
97 final int multiplier;
98 if ((key & flag) == 0x0l) {
99 // no values are stored for this coefficient, it is 0
100 multiplier = 0;
101 } else {
102 // there is a stored value for this coefficient
103 multiplier = ((int) ((key >>> shift) & 0x7Fl)) - 64;
104 shift += 7;
105 }
106
107 // update bit mask
108 flag = flag << 1;
109
110 return multiplier;
111
112 }
113
114 /** Encode all tide, Delaunay and planetary multipliers into one key.
115 * @param multipliers multipliers to encode
116 * @return a key merging all multipliers as one long integer
117 */
118 public static long encode(final int... multipliers) {
119 final NutationCodec encoder = new NutationCodec(0x0l);
120 for (final int multiplier : multipliers) {
121 encoder.addMultiplier(multiplier);
122 }
123 return encoder.getKey();
124 }
125
126 /** Decode a key into all tide, Delaunay and planetary multipliers.
127 * @param key key merging all multipliers as one long integer
128 * @return all tide, Delaunay and planetary multiplers, in the order
129 * cGamma, cL, cLPrime, cF, cD, cOmega, cMe, cVe, cE, cMa, cJu, cSa, cUr, cNe, cPa
130 */
131 public static int[] decode(final long key) {
132 final int[] multipliers = new int[15];
133 final NutationCodec decoder = new NutationCodec(key);
134 for (int i = 0; i < multipliers.length; ++i) {
135 multipliers[i] = decoder.nextMultiplier();
136 }
137 return multipliers;
138 }
139
140 }