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