IGSUtils.java

  1. /* Copyright 2022-2025 Thales Alenia Space
  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.gnss;

  18. import org.orekit.annotation.DefaultDataContext;
  19. import org.orekit.data.DataContext;
  20. import org.orekit.errors.OrekitException;
  21. import org.orekit.errors.OrekitMessages;
  22. import org.orekit.frames.Frame;
  23. import org.orekit.frames.Frames;
  24. import org.orekit.frames.ITRFVersion;
  25. import org.orekit.frames.Predefined;
  26. import org.orekit.frames.VersionedITRF;
  27. import org.orekit.utils.IERSConventions;

  28. import java.util.Locale;
  29. import java.util.regex.Matcher;
  30. import java.util.regex.Pattern;

  31. /** Utility for IGS files.
  32.  * @author Luc Maisonobe
  33.  * @since 12.1
  34.  *
  35.  */
  36. public class IGSUtils {

  37.     /** Pattern for frame names with year.
  38.      * @since 12.1
  39.      */
  40.     private static final Pattern EARTH_FRAME_WITH_YEAR = Pattern.compile("(?:IER|ITR|ITRF|IGS|IGb|SLR)([0-9]{2})");

  41.     /** Pattern for GCRF inertial frame.
  42.      * @since 12.1
  43.      */
  44.     private static final Pattern GCRF_FRAME = Pattern.compile(" *GCRF *");

  45.     /** Pattern for EME2000 inertial frame.
  46.      * @since 12.1
  47.      */
  48.     private static final Pattern EME2000_FRAME = Pattern.compile("EME(?:00|2K)");

  49.     /** Private constructor for a utility class.
  50.      */
  51.     private IGSUtils() {
  52.         // nothing to do
  53.     }

  54.     /** Default string to {@link Frame} conversion for {@link org.orekit.files.sp3.SP3Parser}
  55.      * or {@link org.orekit.files.rinex.clock.RinexClockParser}.
  56.      *
  57.      * <p>
  58.      * This method uses the {@link DataContext#getDefault() default data context}.
  59.      * </p>
  60.      * <p>
  61.      * Various frame names are supported:
  62.      * </p>
  63.      * <ul>
  64.      *     <li>IER##, ITR##, ITRF##, IGS##, IGb##, or SLR##, where ## is a two digits number,
  65.      *         the number will be used to build the appropriate {@link ITRFVersion}</li>
  66.      *     <li>GCRF (left or right justified) for GCRF inertial frame</li>
  67.      *     <li>EME00 or EME2K for EME2000 inertial frame</li>
  68.      *     <li>for all other names (for example if name is UNDEF or WGS84),
  69.      *     then a default {@link org.orekit.frames.Frames#getITRF(IERSConventions, boolean) ITRF}
  70.      *     frame will be selected</li>
  71.      * </ul>
  72.      * <p>
  73.      * Note that using inertial frames in classical products like SP3 files is non-standard,
  74.      * it is supported by Orekit, but may not be supported by other programs, so they should
  75.      * be used with caution when writing files.
  76.      * </p>
  77.      *
  78.      * @param name of the frame.
  79.      * @return ITRF based on 2010 conventions,
  80.      * with tidal effects considered during EOP interpolation
  81.      * @since 12.1
  82.      */
  83.     @DefaultDataContext
  84.     public static Frame guessFrame(final String name) {
  85.         return guessFrame(DataContext.getDefault().getFrames(), name);
  86.     }

  87.     /** Default string to {@link Frame} conversion for {@link org.orekit.files.sp3.SP3Parser}
  88.      * or {@link org.orekit.files.rinex.clock.RinexClockParser}.
  89.      *
  90.      * <p>
  91.      * Various frame names are supported:
  92.      * </p>
  93.      * <ul>
  94.      *     <li>IER##, ITR##, ITRF##, IGS##, IGb##, or SLR##, where ## is a two digits number,
  95.      *         the number will be used to build the appropriate {@link ITRFVersion}</li>
  96.      *     <li>GCRF (left or right justified) for GCRF inertial frame</li>
  97.      *     <li>EME00 or EME2K for EME2000 inertial frame</li>
  98.      *     <li>for all other names (for example if name is UNDEF or WGS84),
  99.      *     then a default {@link org.orekit.frames.Frames#getITRF(IERSConventions, boolean) ITRF}
  100.      *     frame will be selected</li>
  101.      * </ul>
  102.      * <p>
  103.      * Note that using inertial frames in classical products like SP3 files is non-standard,
  104.      * it is supported by Orekit, but may not be supported by other programs, so they should
  105.      * be used with caution when writing files.
  106.      * </p>
  107.      *
  108.      * @param frames frames factory
  109.      * @param name of the frame.
  110.      * @return guessed frame
  111.      * @since 12.1
  112.      */
  113.     public static Frame guessFrame(final Frames frames, final String name) {
  114.         final Matcher earthMatcher = EARTH_FRAME_WITH_YEAR.matcher(name);
  115.         if (earthMatcher.matches()) {
  116.             // this is a frame of the form IGS14, or ITR20, or SLR08, or similar
  117.             final int yy = Integer.parseInt(earthMatcher.group(1));
  118.             final ITRFVersion itrfVersion = ITRFVersion.getITRFVersion(yy);
  119.             final IERSConventions conventions =
  120.                 itrfVersion.getYear() < 2003 ?
  121.                 IERSConventions.IERS_1996 :
  122.                 (itrfVersion.getYear() < 2010 ? IERSConventions.IERS_2003 : IERSConventions.IERS_2010);
  123.             return frames.getITRF(itrfVersion, conventions, false);
  124.         } else {
  125.             final Matcher gcrfMatcher = GCRF_FRAME.matcher(name);
  126.             if (gcrfMatcher.matches()) {
  127.                 // inertial GCRF frame
  128.                 return frames.getGCRF();
  129.             } else {
  130.                 final Matcher eme2000Matcher = EME2000_FRAME.matcher(name);
  131.                 if (eme2000Matcher.matches()) {
  132.                     // inertial EME2000 frame
  133.                     return frames.getEME2000();
  134.                 } else {
  135.                     // unknown frame 'maybe UNDEF or WGS84
  136.                     // we use a default ITRF
  137.                     return frames.getITRF(IERSConventions.IERS_2010, false);
  138.                 }
  139.             }
  140.         }
  141.     }

  142.     /** Guess a frame name.
  143.      * <p>
  144.      * If the frame is not compatible with {@link #guessFrame(Frames, String)},
  145.      * an exception will be triggered
  146.      * </p>
  147.      * @param frame frame from which we want the name
  148.      * @return name compatible with {@link #guessFrame(Frames, String)}
  149.      * @since 12.1
  150.      */
  151.     public static String frameName(final Frame frame) {
  152.         if (frame instanceof VersionedITRF) {
  153.             final int yy = ((VersionedITRF) frame).getITRFVersion().getYear() % 100;
  154.             return String.format(Locale.US, "IGS%02d", yy);
  155.         } else if (Predefined.GCRF.getName().equals(frame.getName())) {
  156.             return "GCRF";
  157.         } else if (Predefined.EME2000.getName().equals(frame.getName())) {
  158.             return "EME2K";
  159.         } else {
  160.             throw new OrekitException(OrekitMessages.FRAME_NOT_ALLOWED, frame.getName());
  161.         }
  162.     }

  163. }