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
19 import org.orekit.annotation.DefaultDataContext;
20 import org.orekit.data.DataContext;
21 import org.orekit.errors.OrekitException;
22 import org.orekit.errors.OrekitMessages;
23 import org.orekit.frames.Frame;
24 import org.orekit.frames.Frames;
25 import org.orekit.frames.ITRFVersion;
26 import org.orekit.frames.Predefined;
27 import org.orekit.frames.VersionedITRF;
28 import org.orekit.utils.IERSConventions;
29
30 import java.util.Locale;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33
34 /** Utility for IGS files.
35 * @author Luc Maisonobe
36 * @since 12.1
37 *
38 */
39 public class IGSUtils {
40
41 /** Pattern for frame names with year.
42 * @since 12.1
43 */
44 private static final Pattern EARTH_FRAME_WITH_YEAR = Pattern.compile("(?:IER|ITR|ITRF|IGS|IGb|SLR)([0-9]{2})");
45
46 /** Pattern for GCRF inertial frame.
47 * @since 12.1
48 */
49 private static final Pattern GCRF_FRAME = Pattern.compile(" *GCRF *");
50
51 /** Pattern for EME2000 inertial frame.
52 * @since 12.1
53 */
54 private static final Pattern EME2000_FRAME = Pattern.compile("EME(?:00|2K)");
55
56 /** Private constructor for a utility class.
57 */
58 private IGSUtils() {
59 // nothing to do
60 }
61
62 /** Default string to {@link Frame} conversion for {@link org.orekit.files.sp3.SP3Parser}
63 * or {@link org.orekit.files.rinex.clock.RinexClockParser}.
64 *
65 * <p>
66 * This method uses the {@link DataContext#getDefault() default data context}.
67 * </p>
68 * <p>
69 * Various frame names are supported:
70 * </p>
71 * <ul>
72 * <li>IER##, ITR##, ITRF##, IGS##, IGb##, or SLR##, where ## is a two digits number,
73 * the number will be used to build the appropriate {@link ITRFVersion}</li>
74 * <li>GCRF (left or right justified) for GCRF inertial frame</li>
75 * <li>EME00 or EME2K for EME2000 inertial frame</li>
76 * <li>for all other names (for example if name is UNDEF or WGS84),
77 * then a default {@link org.orekit.frames.Frames#getITRF(IERSConventions, boolean) ITRF}
78 * frame will be selected</li>
79 * </ul>
80 * <p>
81 * Note that using inertial frames in classical products like SP3 files is non-standard,
82 * it is supported by Orekit, but may not be supported by other programs, so they should
83 * be used with caution when writing files.
84 * </p>
85 *
86 * @param name of the frame.
87 * @return ITRF based on 2010 conventions,
88 * with tidal effects considered during EOP interpolation
89 * @since 12.1
90 */
91 @DefaultDataContext
92 public static Frame guessFrame(final String name) {
93 return guessFrame(DataContext.getDefault().getFrames(), name);
94 }
95
96 /** Default string to {@link Frame} conversion for {@link org.orekit.files.sp3.SP3Parser}
97 * or {@link org.orekit.files.rinex.clock.RinexClockParser}.
98 *
99 * <p>
100 * Various frame names are supported:
101 * </p>
102 * <ul>
103 * <li>IER##, ITR##, ITRF##, IGS##, IGb##, or SLR##, where ## is a two digits number,
104 * the number will be used to build the appropriate {@link ITRFVersion}</li>
105 * <li>GCRF (left or right justified) for GCRF inertial frame</li>
106 * <li>EME00 or EME2K for EME2000 inertial frame</li>
107 * <li>for all other names (for example if name is UNDEF or WGS84),
108 * then a default {@link org.orekit.frames.Frames#getITRF(IERSConventions, boolean) ITRF}
109 * frame will be selected</li>
110 * </ul>
111 * <p>
112 * Note that using inertial frames in classical products like SP3 files is non-standard,
113 * it is supported by Orekit, but may not be supported by other programs, so they should
114 * be used with caution when writing files.
115 * </p>
116 *
117 * @param frames frames factory
118 * @param name of the frame.
119 * @return guessed frame
120 * @since 12.1
121 */
122 public static Frame guessFrame(final Frames frames, final String name) {
123 final Matcher earthMatcher = EARTH_FRAME_WITH_YEAR.matcher(name);
124 if (earthMatcher.matches()) {
125 // this is a frame of the form IGS14, or ITR20, or SLR08, or similar
126 final int yy = Integer.parseInt(earthMatcher.group(1));
127 final ITRFVersion itrfVersion = ITRFVersion.getITRFVersion(yy);
128 final IERSConventions conventions =
129 itrfVersion.getYear() < 2003 ?
130 IERSConventions.IERS_1996 :
131 (itrfVersion.getYear() < 2010 ? IERSConventions.IERS_2003 : IERSConventions.IERS_2010);
132 return frames.getITRF(itrfVersion, conventions, false);
133 } else {
134 final Matcher gcrfMatcher = GCRF_FRAME.matcher(name);
135 if (gcrfMatcher.matches()) {
136 // inertial GCRF frame
137 return frames.getGCRF();
138 } else {
139 final Matcher eme2000Matcher = EME2000_FRAME.matcher(name);
140 if (eme2000Matcher.matches()) {
141 // inertial EME2000 frame
142 return frames.getEME2000();
143 } else {
144 // unknown frame 'maybe UNDEF or WGS84
145 // we use a default ITRF
146 return frames.getITRF(IERSConventions.IERS_2010, false);
147 }
148 }
149 }
150 }
151
152 /** Guess a frame name.
153 * <p>
154 * If the frame is not compatible with {@link #guessFrame(Frames, String)},
155 * an exception will be triggered
156 * </p>
157 * @param frame frame from which we want the name
158 * @return name compatible with {@link #guessFrame(Frames, String)}
159 * @since 12.1
160 */
161 public static String frameName(final Frame frame) {
162 if (frame instanceof VersionedITRF) {
163 final int yy = ((VersionedITRF) frame).getITRFVersion().getYear() % 100;
164 return String.format(Locale.US, "IGS%02d", yy);
165 } else if (Predefined.GCRF.getName().equals(frame.getName())) {
166 return "GCRF";
167 } else if (Predefined.EME2000.getName().equals(frame.getName())) {
168 return "EME2K";
169 } else {
170 throw new OrekitException(OrekitMessages.FRAME_NOT_ALLOWED, frame.getName());
171 }
172 }
173
174 }