NutationCodec.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.data;

  18. import org.orekit.errors.OrekitInternalError;

  19. /** Encoder/decoder for Delaunay and planetary multipliers keys.
  20.  * <p>
  21.  * As Delaunay and planetary multipliers often have a lot of zeroes
  22.  * and the non-zero multipliers are in a small range, it makes sense
  23.  * to encode them in a compact representation that can be used as
  24.  * a key in hash tables. This class does the encoding/decoding of
  25.  * such keys.
  26.  * </p>
  27.  * <p>
  28.  * The encoding scheme is as follows, numbering bits from
  29.  * 0 for least significant bit to 63 for most significant bit:
  30.  * </p>
  31.  * <ul>
  32.  *   <li>bits  0 to 14: mask for the 15 coefficients</li>
  33.  *   <li>bits 15 to 63: split into 7 slots each 7 bits long and
  34.  *   each encoding a coefficient ci + 64, where ci is the i-th
  35.  *   non-zero coefficient</li>
  36.  * </ul>
  37.  * <p>
  38.  * This scheme allows to encode 7 non-zero integers between -64 to +63 among 15.
  39.  * As the current Poisson series used in Orekit have at most 6 non-zero coefficients
  40.  * and all the coefficients are between -21 and +20, we have some extension margin.
  41.  * </p>
  42.  */
  43. class NutationCodec {

  44.     /** Current multiplier flag bit. */
  45.     private long flag;

  46.     /** Current coefficient shift. */
  47.     private int shift;

  48.     /** Current key value. */
  49.     private long key;

  50.     /** Simple constructor.
  51.      * @param key key
  52.      */
  53.     private NutationCodec(final long key) {
  54.         flag  = 0x1l;
  55.         shift = 15;
  56.         this.key = key;
  57.     }

  58.     /** Get the key value.
  59.      * @return key value
  60.      */
  61.     public long getKey() {
  62.         return key;
  63.     }

  64.     /** Encode one more multiplier in the key.
  65.      * @param multiplier multiplier to encode
  66.      */
  67.     private void addMultiplier(final int multiplier) {

  68.         if (multiplier != 0) {
  69.             // this is a coefficient we want to store
  70.             key = key | flag;
  71.             if (shift > 57 || multiplier < -64 || multiplier > 63) {
  72.                 // this should never happen, we exceed the encoding capacity
  73.                 throw new OrekitInternalError(null);
  74.             }
  75.             key    = key | (((multiplier + 64l) & 0x7Fl) << shift);
  76.             shift += 7;
  77.         }

  78.         // update bit mask
  79.         flag = flag << 1;

  80.     }

  81.     /** Decode one multiplier from the key.
  82.      * @return decoded multiplier
  83.      */
  84.     private int nextMultiplier() {
  85.         final int multiplier;
  86.         if ((key & flag) == 0x0l) {
  87.             // no values are stored for this coefficient, it is 0
  88.             multiplier = 0;
  89.         } else {
  90.             // there is a stored value for this coefficient
  91.             multiplier = ((int) ((key >>> shift) & 0x7Fl)) - 64;
  92.             shift += 7;
  93.         }

  94.         // update bit mask
  95.         flag = flag << 1;

  96.         return multiplier;

  97.     }

  98.     /** Encode all tide, Delaunay and planetary multipliers into one key.
  99.      * @param multipliers multipliers to encode
  100.      * @return a key merging all multipliers as one long integer
  101.      */
  102.     public static long encode(final int... multipliers) {
  103.         final NutationCodec encoder = new NutationCodec(0x0l);
  104.         for (final int multiplier : multipliers) {
  105.             encoder.addMultiplier(multiplier);
  106.         }
  107.         return encoder.getKey();
  108.     }

  109.     /** Decode a key into all tide, Delaunay and planetary multipliers.
  110.      * @param key key merging all multipliers as one long integer
  111.      * @return all tide, Delaunay and planetary multiplers, in the order
  112.      * cGamma, cL, cLPrime, cF, cD, cOmega, cMe, cVe, cE, cMa, cJu, cSa, cUr, cNe, cPa
  113.      */
  114.     public static int[] decode(final long key) {
  115.         final int[] multipliers = new int[15];
  116.         final NutationCodec decoder = new NutationCodec(key);
  117.         for (int i = 0; i < multipliers.length; ++i) {
  118.             multipliers[i] = decoder.nextMultiplier();
  119.         }
  120.         return multipliers;
  121.     }

  122. }