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.files.sinex;
18  
19  import org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.orekit.errors.OrekitException;
21  import org.orekit.errors.OrekitMessages;
22  import org.orekit.files.sinex.Station.ReferenceSystem;
23  import org.orekit.gnss.GnssSignal;
24  import org.orekit.gnss.PredefinedGnssSignal;
25  import org.orekit.gnss.SatInSystem;
26  import org.orekit.gnss.SatelliteSystem;
27  import org.orekit.time.AbsoluteDate;
28  
29  import java.util.function.Predicate;
30  
31  /** Predicates for blocks containing a single type of lines.
32   * @author Luc Maisonobe
33   * @since 13.0
34   */
35  enum SingleLineBlockPredicate implements Predicate<SinexParseInfo> {
36  
37      /** Predicate for SITE/ID block content. */
38      SITE_ID {
39          /** {@inheritDoc} */
40          @Override
41          public void parse(final SinexParseInfo parseInfo) {
42              // read site id. data
43              final Station station = new Station();
44              station.setSiteCode(parseInfo.parseString(1, 4));
45              station.setDomes(parseInfo.parseString(9, 9));
46              parseInfo.addStation(station);
47          }
48      },
49  
50      /** Predicate for SITE/ANTENNA block content. */
51      SITE_ANTENNA {
52          /** {@inheritDoc} */
53          @Override
54          public void parse(final SinexParseInfo parseInfo) {
55  
56              // read antenna type data
57              final Station station = parseInfo.getCurrentLineStation(1);
58  
59              // validity range
60              final AbsoluteDate start = parseInfo.getCurrentLineStartDate();
61              final AbsoluteDate end   = parseInfo.getCurrentLineEndDate();
62  
63              // antenna key
64              final AntennaKey key = new AntennaKey(parseInfo.parseString(42, 16),
65                                                    parseInfo.parseString(58,  4),
66                                                    parseInfo.parseString(63,  5));
67  
68              // special implementation for the first entry
69              if (station.getAntennaKeyTimeSpanMap().getSpansNumber() == 1) {
70                  // we want null values outside validity limits of the station
71                  station.addAntennaKeyValidBefore(key, end);
72                  station.addAntennaKeyValidBefore(null, start);
73              } else {
74                  station.addAntennaKeyValidBefore(key, end);
75              }
76  
77          }
78      },
79  
80      /** Predicate for SITE/ECCENTRICITY block content. */
81      SITE_ECCENTRICITY {
82          /** {@inheritDoc} */
83          @Override
84          public void parse(final SinexParseInfo parseInfo) {
85  
86              // read antenna eccentricities data
87              final Station station = parseInfo.getCurrentLineStation(1);
88  
89              // validity range
90              final AbsoluteDate start = parseInfo.getCurrentLineStartDate();
91              final AbsoluteDate end = parseInfo.getCurrentLineEndDate();
92  
93              // reference system UNE or XYZ
94              station.setEccRefSystem(ReferenceSystem.getEccRefSystem(parseInfo.parseString(42, 3)));
95  
96              // eccentricity vector
97              final Vector3D eccStation = new Vector3D(parseInfo.parseDouble(46, 8),
98                                                       parseInfo.parseDouble(55, 8),
99                                                       parseInfo.parseDouble(64, 8));
100 
101             // special implementation for the first entry
102             if (station.getEccentricitiesTimeSpanMap().getSpansNumber() == 1) {
103                 // we want null values outside validity limits of the station
104                 station.addStationEccentricitiesValidBefore(eccStation, end);
105                 station.addStationEccentricitiesValidBefore(null, start);
106             } else {
107                 station.addStationEccentricitiesValidBefore(eccStation, end);
108             }
109 
110         }
111     },
112 
113     /** Predicate for SOLUTION/EPOCHS block content. */
114     SOLUTION_EPOCHS {
115         /** {@inheritDoc} */
116         @Override
117         public void parse(final SinexParseInfo parseInfo) {
118 
119             // station
120             final Station station = parseInfo.getCurrentLineStation(1);
121 
122             // validity range
123             station.setValidFrom(parseInfo.getCurrentLineStartDate());
124             station.setValidUntil(parseInfo.getCurrentLineEndDate());
125 
126         }
127     },
128 
129     /** Predicate for SITE/GPS_PHASE_CENTER block content. */
130     SITE_GPS_PHASE_CENTER {
131         /** {@inheritDoc} */
132         @Override
133         public void parse(final SinexParseInfo parseInfo) {
134 
135             // antenna key
136             final AntennaKey key = new AntennaKey(parseInfo.parseString(1, 16),
137                                                   parseInfo.parseString(17, 4),
138                                                   parseInfo.parseString(22, 5));
139 
140             // phase center for first signal in current line
141             final Vector3D phaseCenter1 = new Vector3D(parseInfo.parseDouble(28, 6),
142                                                        parseInfo.parseDouble(35, 6),
143                                                        parseInfo.parseDouble(42, 6));
144             parseInfo.addStationPhaseCenter(key, phaseCenter1, GPS_SIGNALS);
145 
146             // phase center for second signal in current line
147             final Vector3D phaseCenter2 = new Vector3D(parseInfo.parseDouble(49, 6),
148                                                        parseInfo.parseDouble(56, 6),
149                                                        parseInfo.parseDouble(63, 6));
150             parseInfo.addStationPhaseCenter(key, phaseCenter2, GPS_SIGNALS);
151 
152         }
153     },
154 
155     /** Predicate for SITE/GAL_PHASE_CENTER block content. */
156     SITE_GAL_PHASE_CENTER {
157         /** {@inheritDoc} */
158         @Override
159         public void parse(final SinexParseInfo parseInfo) {
160 
161             // antenna key
162             final AntennaKey key = new AntennaKey(parseInfo.parseString(1, 16),
163                                                   parseInfo.parseString(17, 4),
164                                                   parseInfo.parseString(22, 5));
165 
166             // phase center for first signal in current line
167             final Vector3D phaseCenter1 = new Vector3D(parseInfo.parseDouble(28, 6),
168                                                        parseInfo.parseDouble(35, 6),
169                                                        parseInfo.parseDouble(42, 6));
170             parseInfo.addStationPhaseCenter(key, phaseCenter1, GALILEO_SIGNALS);
171 
172             if (!parseInfo.parseString(49, 6).trim().isEmpty()) {
173                 // phase center for second signal in current line
174                 final Vector3D phaseCenter2 = new Vector3D(parseInfo.parseDouble(49, 6),
175                                                            parseInfo.parseDouble(56, 6),
176                                                            parseInfo.parseDouble(63, 6));
177                 parseInfo.addStationPhaseCenter(key, phaseCenter2, GALILEO_SIGNALS);
178             }
179 
180         }
181     },
182 
183     /** Predicate for SATELLITE/PHASE_CENTER block content. */
184     SATELLITE_PHASE_CENTER {
185         /** {@inheritDoc} */
186         @Override
187         public void parse(final SinexParseInfo parseInfo) {
188 
189             // satellite id
190             final SatInSystem satInSystem = new SatInSystem(parseInfo.parseString(1, 4));
191 
192             // first signal in current line
193             final GnssSignal signal1     = decode(satInSystem.getSystem(), parseInfo.parseInt(6, 1), parseInfo);
194             // beware! the fields are in order Z, X, Y in the file
195             final Vector3D   phaseCenter1 = new Vector3D(parseInfo.parseDouble(15, 6),
196                                                          parseInfo.parseDouble(22, 6),
197                                                          parseInfo.parseDouble( 8, 6));
198             parseInfo.addSatellitePhaseCenter(satInSystem, signal1, phaseCenter1);
199 
200             if (!parseInfo.parseString(31, 6).trim().isEmpty()) {
201                 // second signal in current line
202                 final GnssSignal signal2      = decode(satInSystem.getSystem(), parseInfo.parseInt(29, 1), parseInfo);
203                 // beware! the fields are in order Z, X, Y in the file
204                 final Vector3D   phaseCenter2 = new Vector3D(parseInfo.parseDouble(38, 6),
205                                                              parseInfo.parseDouble(45, 6),
206                                                              parseInfo.parseDouble(31, 6));
207                 parseInfo.addSatellitePhaseCenter(satInSystem, signal2, phaseCenter2);
208             }
209 
210         }
211 
212         /** Decode GNSS signal.
213          * @param system satellite system
214          * @param code frequency code
215          * @param parseInfo holder for parse info
216          * @return GNSS signal
217          */
218         private GnssSignal decode(final SatelliteSystem system, final int code, final SinexParseInfo parseInfo) {
219             if (system == SatelliteSystem.GPS) {
220                 if (code == 1) {
221                     return PredefinedGnssSignal.G01;
222                 } else if (code == 2) {
223                     return PredefinedGnssSignal.G02;
224                 } else if (code == 5) {
225                     return PredefinedGnssSignal.G05;
226                 }
227             } else if (system == SatelliteSystem.GALILEO) {
228                 if (code == 1) {
229                     return PredefinedGnssSignal.E01;
230                 } else if (code == 5) {
231                     return PredefinedGnssSignal.E05;
232                 } else if (code == 6) {
233                     return PredefinedGnssSignal.E06;
234                 } else if (code == 7) {
235                     return PredefinedGnssSignal.E07;
236                 } else if (code == 8) {
237                     return PredefinedGnssSignal.E08;
238                 }
239             } else if (system == SatelliteSystem.GLONASS) {
240                 if (code == 1) {
241                     // here, the SINEX specification lists L1 frequency, R01 is the closest one
242                     return PredefinedGnssSignal.R01;
243                 } else if (code == 2) {
244                     // here, the SINEX specification lists L2 frequency, R02 is the closest one
245                     return PredefinedGnssSignal.R02;
246                 } else if (code == 5) {
247                     // here, the SINEX specification lists L5 frequency, R03 is the closest one
248                     return PredefinedGnssSignal.R03;
249                 }
250             } else if (system == SatelliteSystem.QZSS) {
251                 // this is not in the SINEX specification, but some files use it
252                 if (code == 1) {
253                     return PredefinedGnssSignal.J01;
254                 } else if (code == 2) {
255                     return PredefinedGnssSignal.J02;
256                 } else if (code == 5) {
257                     return PredefinedGnssSignal.J05;
258                 }
259             }
260             throw new OrekitException(OrekitMessages.UNKNOWN_GNSS_FREQUENCY,
261                                       system, code, parseInfo.getLineNumber(), parseInfo.getName());
262         }
263 
264     };
265 
266     /** Signals used for SITE/GPS_PHASE_CENTER. */
267     private static final PredefinedGnssSignal[] GPS_SIGNALS =
268         new PredefinedGnssSignal[] {
269             PredefinedGnssSignal.G01, PredefinedGnssSignal.G02
270         };
271 
272     /** Signals used for SITE/GAL_PHASE_CENTER. */
273     private static final PredefinedGnssSignal[] GALILEO_SIGNALS =
274         new PredefinedGnssSignal[] {
275             PredefinedGnssSignal.E01, PredefinedGnssSignal.E05,
276             PredefinedGnssSignal.E06, PredefinedGnssSignal.E07,
277             PredefinedGnssSignal.E08
278         };
279 
280     /** {@inheritDoc} */
281     @Override
282     public boolean test(final SinexParseInfo parseInfo) {
283         if (parseInfo.getLine().charAt(0) != '-') {
284             parse(parseInfo);
285             return true;
286         } else {
287             return false;
288         }
289     }
290 
291     /** Parse one line.
292      * @param parseInfo container for parse info
293      */
294     protected abstract void parse(SinexParseInfo parseInfo);
295 
296 }