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