1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.odm.omm;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.function.Function;
23
24 import org.hipparchus.util.FastMath;
25 import org.orekit.data.DataContext;
26 import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
27 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
28 import org.orekit.files.ccsds.ndm.odm.CartesianCovariance;
29 import org.orekit.files.ccsds.ndm.odm.CartesianCovarianceKey;
30 import org.orekit.files.ccsds.ndm.odm.OdmCommonMetadata;
31 import org.orekit.files.ccsds.ndm.odm.CommonMetadataKey;
32 import org.orekit.files.ccsds.ndm.odm.KeplerianElements;
33 import org.orekit.files.ccsds.ndm.odm.KeplerianElementsKey;
34 import org.orekit.files.ccsds.ndm.odm.OdmHeader;
35 import org.orekit.files.ccsds.ndm.odm.OdmMetadataKey;
36 import org.orekit.files.ccsds.ndm.odm.OdmParser;
37 import org.orekit.files.ccsds.ndm.odm.SpacecraftParameters;
38 import org.orekit.files.ccsds.ndm.odm.SpacecraftParametersKey;
39 import org.orekit.files.ccsds.ndm.odm.UserDefined;
40 import org.orekit.files.ccsds.section.CommentsContainer;
41 import org.orekit.files.ccsds.section.HeaderProcessingState;
42 import org.orekit.files.ccsds.section.MetadataKey;
43 import org.orekit.files.ccsds.section.Segment;
44 import org.orekit.files.ccsds.section.XmlStructureProcessingState;
45 import org.orekit.files.ccsds.utils.ContextBinding;
46 import org.orekit.files.ccsds.utils.FileFormat;
47 import org.orekit.files.ccsds.utils.lexical.ParseToken;
48 import org.orekit.files.ccsds.utils.lexical.TokenType;
49 import org.orekit.files.ccsds.utils.lexical.UserDefinedXmlTokenBuilder;
50 import org.orekit.files.ccsds.utils.lexical.XmlTokenBuilder;
51 import org.orekit.files.ccsds.utils.parsing.ErrorState;
52 import org.orekit.files.ccsds.utils.parsing.ProcessingState;
53 import org.orekit.frames.Frame;
54 import org.orekit.propagation.analytical.tle.TLEPropagator;
55 import org.orekit.time.AbsoluteDate;
56 import org.orekit.utils.IERSConventions;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public class OmmParser extends OdmParser<Omm, OmmParser> {
72
73
74 private final double defaultMass;
75
76
77 private OdmHeader header;
78
79
80 private List<Segment<OmmMetadata, OmmData>> segments;
81
82
83 private OmmMetadata metadata;
84
85
86 private ContextBinding context;
87
88
89 private KeplerianElements keplerianElementsBlock;
90
91
92 private SpacecraftParameters spacecraftParametersBlock;
93
94
95 private OmmTle tleBlock;
96
97
98 private CartesianCovariance covarianceBlock;
99
100
101 private UserDefined userDefinedBlock;
102
103
104 private ProcessingState structureProcessor;
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 public OmmParser(final IERSConventions conventions, final boolean simpleEOP,
124 final DataContext dataContext, final AbsoluteDate missionReferenceDate,
125 final double mu, final double defaultMass, final ParsedUnitsBehavior parsedUnitsBehavior,
126 final Function<ParseToken, List<ParseToken>>[] filters,
127 final CcsdsFrameMapper frameMapper) {
128 super(Omm.ROOT, Omm.FORMAT_VERSION_KEY, conventions, simpleEOP, dataContext,
129 missionReferenceDate, mu, parsedUnitsBehavior, filters,
130 frameMapper);
131 this.defaultMass = defaultMass;
132 }
133
134
135 @Override
136 public Map<String, XmlTokenBuilder> getSpecialXmlElementsBuilders() {
137
138 final Map<String, XmlTokenBuilder> builders = super.getSpecialXmlElementsBuilders();
139
140
141 builders.put(UserDefined.USER_DEFINED_XML_TAG, new UserDefinedXmlTokenBuilder());
142
143 return builders;
144
145 }
146
147
148 @Override
149 public OdmHeader getHeader() {
150 return header;
151 }
152
153
154 @Override
155 public void reset(final FileFormat fileFormat) {
156 header = new OdmHeader();
157 segments = new ArrayList<>();
158 metadata = null;
159 context = null;
160 keplerianElementsBlock = null;
161 spacecraftParametersBlock = null;
162 tleBlock = null;
163 covarianceBlock = null;
164 userDefinedBlock = null;
165 if (fileFormat == FileFormat.XML) {
166 structureProcessor = new XmlStructureProcessingState(Omm.ROOT, this);
167 reset(fileFormat, structureProcessor);
168 } else {
169 structureProcessor = new ErrorState();
170 reset(fileFormat, new HeaderProcessingState(this));
171 }
172 }
173
174
175 @Override
176 public boolean prepareHeader() {
177 anticipateNext(new HeaderProcessingState(this));
178 return true;
179 }
180
181
182 @Override
183 public boolean inHeader() {
184 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processMetadataToken);
185 return true;
186 }
187
188
189 @Override
190 public boolean finalizeHeader() {
191 header.validate(header.getFormatVersion());
192 return true;
193 }
194
195
196 @Override
197 public boolean prepareMetadata() {
198 if (metadata != null) {
199 return false;
200 }
201 metadata = new OmmMetadata(getFrameMapper());
202 context = new ContextBinding(this::getConventions, this::isSimpleEOP,
203 this::getDataContext, this::getParsedUnitsBehavior,
204 this::getMissionReferenceDate,
205 metadata::getTimeSystem, () -> 0.0, () -> 1.0);
206 anticipateNext(this::processMetadataToken);
207 return true;
208 }
209
210
211 @Override
212 public boolean inMetadata() {
213 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processKeplerianElementsToken);
214 return true;
215 }
216
217
218 @Override
219 public boolean finalizeMetadata() {
220 metadata.finalizeMetadata(context);
221 metadata.validate(header.getFormatVersion());
222 if (metadata.getCenter().getBody() != null) {
223 setMuCreated(metadata.getCenter().getBody().getGM());
224 }
225 return true;
226 }
227
228
229 @Override
230 public boolean prepareData() {
231 keplerianElementsBlock = new KeplerianElements();
232 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : this::processKeplerianElementsToken);
233 return true;
234 }
235
236
237 @Override
238 public boolean inData() {
239 return true;
240 }
241
242
243 @Override
244 public boolean finalizeData() {
245 if (metadata != null) {
246 if (userDefinedBlock != null && userDefinedBlock.getParameters().isEmpty()) {
247 userDefinedBlock = null;
248 }
249 if (tleBlock != null) {
250 if (Double.isNaN(keplerianElementsBlock.getMu())) {
251 keplerianElementsBlock.setMu(TLEPropagator.getMU());
252 }
253 final double mu = keplerianElementsBlock.getMu();
254 final double n = keplerianElementsBlock.getMeanMotion();
255 keplerianElementsBlock.setA(FastMath.cbrt(mu / (n * n)));
256 setMuParsed(mu);
257 }
258 final double mass = spacecraftParametersBlock == null ?
259 defaultMass : spacecraftParametersBlock.getMass();
260 final OmmData data = new OmmData(keplerianElementsBlock, spacecraftParametersBlock,
261 tleBlock, covarianceBlock, userDefinedBlock, mass);
262 data.validate(header.getFormatVersion());
263 segments.add(new Segment<>(metadata, data));
264 }
265 metadata = null;
266 context = null;
267 keplerianElementsBlock = null;
268 spacecraftParametersBlock = null;
269 tleBlock = null;
270 covarianceBlock = null;
271 userDefinedBlock = null;
272 return true;
273 }
274
275
276 @Override
277 public Omm build() {
278
279
280 finalizeData();
281 return new Omm(header, segments, getConventions(), getDataContext());
282 }
283
284
285
286
287
288
289 boolean manageKeplerianElementsSection(final boolean starting) {
290 anticipateNext(starting ? this::processKeplerianElementsToken : structureProcessor);
291 return true;
292 }
293
294
295
296
297
298
299 boolean manageSpacecraftParametersSection(final boolean starting) {
300 anticipateNext(starting ? this::processSpacecraftParametersToken : structureProcessor);
301 return true;
302 }
303
304
305
306
307
308
309 boolean manageTleParametersSection(final boolean starting) {
310 anticipateNext(starting ? this::processTLEToken : structureProcessor);
311 return true;
312 }
313
314
315
316
317
318
319 boolean manageCovarianceSection(final boolean starting) {
320 anticipateNext(starting ? this::processCovarianceToken : structureProcessor);
321 return true;
322 }
323
324
325
326
327
328
329 boolean manageUserDefinedParametersSection(final boolean starting) {
330 anticipateNext(starting ? this::processUserDefinedToken : structureProcessor);
331 return true;
332 }
333
334
335
336
337
338 private boolean processMetadataToken(final ParseToken token) {
339 if (metadata == null) {
340
341
342 prepareMetadata();
343 }
344 inMetadata();
345 try {
346 return token.getName() != null &&
347 MetadataKey.valueOf(token.getName()).process(token, context, metadata);
348 } catch (IllegalArgumentException iaeG) {
349 try {
350 return OdmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
351 } catch (IllegalArgumentException iaeD) {
352 try {
353 return CommonMetadataKey.valueOf(token.getName()).process(token, context, metadata);
354 } catch (IllegalArgumentException iaeC) {
355 try {
356 return OmmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
357 } catch (IllegalArgumentException iaeM) {
358
359 return false;
360 }
361 }
362 }
363 }
364 }
365
366
367
368
369
370 private boolean processXmlSubStructureToken(final ParseToken token) {
371 try {
372 return token.getName() != null &&
373 XmlSubStructureKey.valueOf(token.getName()).process(token, this);
374 } catch (IllegalArgumentException iae) {
375
376 return false;
377 }
378 }
379
380
381
382
383
384 private boolean processKeplerianElementsToken(final ParseToken token) {
385 if (keplerianElementsBlock == null) {
386
387
388 finalizeMetadata();
389
390
391 prepareData();
392 }
393 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : this::processSpacecraftParametersToken);
394 try {
395 return token.getName() != null &&
396 KeplerianElementsKey.valueOf(token.getName()).process(token, context, keplerianElementsBlock);
397 } catch (IllegalArgumentException iae) {
398
399 return false;
400 }
401 }
402
403
404
405
406
407 private boolean processSpacecraftParametersToken(final ParseToken token) {
408 if (spacecraftParametersBlock == null) {
409 spacecraftParametersBlock = new SpacecraftParameters();
410 if (moveCommentsIfEmpty(keplerianElementsBlock, spacecraftParametersBlock)) {
411
412 keplerianElementsBlock = null;
413 }
414 }
415 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : this::processTLEToken);
416 try {
417 return token.getName() != null &&
418 SpacecraftParametersKey.valueOf(token.getName()).process(token, context, spacecraftParametersBlock);
419 } catch (IllegalArgumentException iae) {
420
421 return false;
422 }
423 }
424
425
426
427
428
429 private boolean processTLEToken(final ParseToken token) {
430 if (tleBlock == null) {
431 tleBlock = new OmmTle();
432 if (moveCommentsIfEmpty(spacecraftParametersBlock, tleBlock)) {
433
434 spacecraftParametersBlock = null;
435 }
436 }
437 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : this::processCovarianceToken);
438 try {
439 return token.getName() != null &&
440 OmmTleKey.valueOf(token.getName()).process(token, context, tleBlock);
441 } catch (IllegalArgumentException iae) {
442
443 return false;
444 }
445 }
446
447
448
449
450
451 private boolean processCovarianceToken(final ParseToken token) {
452 if (covarianceBlock == null) {
453
454 final OdmCommonMetadata savedMetadata = metadata;
455 covarianceBlock = new CartesianCovariance(
456 savedMetadata::getReferenceFrame,
457 savedMetadata.getFrameMapper());
458 if (moveCommentsIfEmpty(tleBlock, covarianceBlock)) {
459
460 tleBlock = null;
461 }
462 }
463 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : this::processUserDefinedToken);
464 try {
465 return token.getName() != null &&
466 CartesianCovarianceKey.valueOf(token.getName()).process(token, context, covarianceBlock);
467 } catch (IllegalArgumentException iae) {
468
469 return false;
470 }
471 }
472
473
474
475
476
477 private boolean processUserDefinedToken(final ParseToken token) {
478 if (userDefinedBlock == null) {
479 userDefinedBlock = new UserDefined();
480 if (moveCommentsIfEmpty(covarianceBlock, userDefinedBlock)) {
481
482 covarianceBlock = null;
483 }
484 }
485 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : new ErrorState());
486 if (token.getName().startsWith(UserDefined.USER_DEFINED_PREFIX)) {
487 if (token.getType() == TokenType.ENTRY) {
488 userDefinedBlock.addEntry(token.getName().substring(UserDefined.USER_DEFINED_PREFIX.length()),
489 token.getContentAsNormalizedString());
490 }
491 return true;
492 } else {
493
494 return false;
495 }
496 }
497
498
499
500
501
502
503 private boolean moveCommentsIfEmpty(final CommentsContainer origin, final CommentsContainer destination) {
504 if (origin != null && origin.acceptComments()) {
505
506 for (final String comment : origin.getComments()) {
507 destination.addComment(comment);
508 }
509 return true;
510 } else {
511 return false;
512 }
513 }
514
515 }