1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.weather;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.nio.charset.StandardCharsets;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.SortedSet;
30 import java.util.TreeSet;
31 import java.util.regex.Pattern;
32
33 import org.hipparchus.util.FastMath;
34 import org.orekit.data.DataLoader;
35 import org.orekit.errors.OrekitException;
36 import org.orekit.errors.OrekitMessages;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 class GptNParser implements DataLoader {
65
66
67 private static final String COMMENT = "%";
68
69
70 private static final Pattern SEPARATOR = Pattern.compile("\\s+");
71
72
73 private static final String LATITUDE_LABEL = "lat";
74
75
76 private static final String LONGITUDE_LABEL = "lon";
77
78
79 private static final String UNDULATION_LABEL = "undu";
80
81
82 private static final String HEIGHT_CORRECTION_LABEL = "Hs";
83
84
85 private static final String A1 = "A1";
86
87
88 private static final String B1 = "B1";
89
90
91 private static final String A2 = "A2";
92
93
94 private static final String B2 = "B2";
95
96
97 private final SeasonalModelType[] expected;
98
99
100 private int latitudeIndex;
101
102
103 private int longitudeIndex;
104
105
106 private int undulationIndex;
107
108
109 private int heightCorrectionIndex;
110
111
112 private int maxIndex;
113
114
115 private final int[] expectedIndices;
116
117
118 private Grid grid;
119
120
121
122
123 GptNParser(final SeasonalModelType... expected) {
124 this.expected = expected.clone();
125 this.expectedIndices = new int[expected.length];
126 }
127
128 @Override
129 public boolean stillAcceptsData() {
130 return grid == null;
131 }
132
133 @Override
134 public void loadData(final InputStream input, final String name) throws IOException {
135
136 final SortedSet<Integer> latSample = new TreeSet<>();
137 final SortedSet<Integer> lonSample = new TreeSet<>();
138 final List<GridEntry> entries = new ArrayList<>();
139
140
141 try (InputStreamReader isr = new InputStreamReader(input, StandardCharsets.UTF_8);
142 BufferedReader br = new BufferedReader(isr)) {
143 int lineNumber = 0;
144 String line;
145 for (line = br.readLine(); line != null; line = br.readLine()) {
146 ++lineNumber;
147 line = line.trim();
148 if (lineNumber == 1) {
149
150 parseHeader(line, lineNumber, name);
151 } else if (!line.isEmpty()) {
152
153 final GridEntry entry = parseEntry(line, lineNumber, name);
154 latSample.add(entry.getLatKey());
155 lonSample.add(entry.getLonKey());
156 entries.add(entry);
157 }
158
159 }
160 }
161
162
163 grid = new Grid(latSample, lonSample, entries, name);
164
165 }
166
167
168
169
170
171
172 private void parseHeader(final String line, final int lineNumber, final String name) {
173
174
175 latitudeIndex = -1;
176 longitudeIndex = -1;
177 undulationIndex = -1;
178 heightCorrectionIndex = -1;
179 maxIndex = -1;
180 Arrays.fill(expectedIndices, -1);
181
182 final String[] fields = SEPARATOR.split(line.substring(COMMENT.length()).trim());
183 String lookingFor = LATITUDE_LABEL;
184 for (int i = 0; i < fields.length; ++i) {
185 maxIndex = FastMath.max(maxIndex, i);
186 checkLabel(fields[i], lookingFor, line, lineNumber, name);
187 switch (fields[i]) {
188 case LATITUDE_LABEL :
189 latitudeIndex = i;
190 lookingFor = LONGITUDE_LABEL;
191 break;
192 case LONGITUDE_LABEL :
193 lookingFor = null;
194 longitudeIndex = i;
195 break;
196 case UNDULATION_LABEL :
197 lookingFor = HEIGHT_CORRECTION_LABEL;
198 undulationIndex = i;
199 break;
200 case HEIGHT_CORRECTION_LABEL :
201 lookingFor = null;
202 heightCorrectionIndex = i;
203 break;
204 case A1 :
205 lookingFor = B1;
206 break;
207 case B1 :
208 lookingFor = A2;
209 break;
210 case A2 :
211 lookingFor = B2;
212 break;
213 case B2 :
214 lookingFor = null;
215 break;
216 default : {
217 final SeasonalModelType type = SeasonalModelType.parseType(fields[i]);
218 for (int j = 0; j < expected.length; ++j) {
219 if (type == expected[j]) {
220 expectedIndices[j] = i;
221 lookingFor = A1;
222 break;
223 }
224 }
225 }
226 }
227 }
228
229
230 int minIndex = FastMath.min(latitudeIndex,
231 FastMath.min(longitudeIndex,
232 FastMath.min(undulationIndex,
233 heightCorrectionIndex)));
234 for (int index : expectedIndices) {
235 minIndex = FastMath.min(minIndex, index);
236 }
237 if (minIndex < 0) {
238
239 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
240 lineNumber, name, line);
241 }
242
243 }
244
245
246
247
248
249
250
251
252 private void checkLabel(final String label, final String lookingFor,
253 final String line, final int lineNumber, final String name) {
254 if (lookingFor != null && !lookingFor.equals(label)) {
255 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
256 lineNumber, name, line);
257 }
258 }
259
260
261
262
263
264
265
266 private GridEntry parseEntry(final String line, final int lineNumber, final String name) {
267 try {
268
269 final String[] fields = SEPARATOR.split(line);
270 if (fields.length != maxIndex + 1) {
271 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
272 lineNumber, name, line);
273 }
274
275 final double latDegree = Double.parseDouble(fields[latitudeIndex]);
276 final double lonDegree = Double.parseDouble(fields[longitudeIndex]);
277
278 final Map<SeasonalModelType, SeasonalModel> models = new HashMap<>(expected.length);
279 for (int i = 0; i < expected.length; ++i) {
280 final int first = expectedIndices[i];
281 models.put(expected[i], new SeasonalModel(Double.parseDouble(fields[first ]),
282 Double.parseDouble(fields[first + 1]),
283 Double.parseDouble(fields[first + 2]),
284 Double.parseDouble(fields[first + 3]),
285 Double.parseDouble(fields[first + 4])));
286 }
287
288 return new GridEntry(FastMath.toRadians(latDegree),
289 (int) FastMath.rint(latDegree * GridEntry.DEG_TO_MAS),
290 FastMath.toRadians(lonDegree),
291 (int) FastMath.rint(lonDegree * GridEntry.DEG_TO_MAS),
292 Double.parseDouble(fields[undulationIndex]),
293 Double.parseDouble(fields[heightCorrectionIndex]),
294 models);
295
296 } catch (NumberFormatException nfe) {
297 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
298 lineNumber, name, line);
299 }
300 }
301
302
303
304
305 public Grid getGrid() {
306 return grid;
307 }
308
309 }