1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.analytical.tle;
18
19 import java.io.Serializable;
20 import java.text.DecimalFormat;
21 import java.text.DecimalFormatSymbols;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Objects;
26
27 import org.hipparchus.CalculusFieldElement;
28 import org.hipparchus.Field;
29 import org.hipparchus.geometry.euclidean.threed.Rotation;
30 import org.hipparchus.util.ArithmeticUtils;
31 import org.hipparchus.util.FastMath;
32 import org.hipparchus.util.MathArrays;
33 import org.hipparchus.util.MathUtils;
34 import org.orekit.annotation.DefaultDataContext;
35 import org.orekit.attitudes.InertialProvider;
36 import org.orekit.data.DataContext;
37 import org.orekit.errors.OrekitException;
38 import org.orekit.errors.OrekitInternalError;
39 import org.orekit.errors.OrekitMessages;
40 import org.orekit.frames.Frame;
41 import org.orekit.orbits.FieldEquinoctialOrbit;
42 import org.orekit.orbits.FieldKeplerianOrbit;
43 import org.orekit.orbits.FieldOrbit;
44 import org.orekit.orbits.OrbitType;
45 import org.orekit.orbits.PositionAngle;
46 import org.orekit.propagation.FieldSpacecraftState;
47 import org.orekit.time.DateComponents;
48 import org.orekit.time.DateTimeComponents;
49 import org.orekit.time.FieldAbsoluteDate;
50 import org.orekit.time.FieldTimeStamped;
51 import org.orekit.time.TimeComponents;
52 import org.orekit.time.TimeScale;
53 import org.orekit.utils.ParameterDriver;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class FieldTLE<T extends CalculusFieldElement<T>> implements FieldTimeStamped<T>, Serializable {
74
75
76 public static final int DEFAULT = 0;
77
78
79 public static final int SGP = 1;
80
81
82 public static final int SGP4 = 2;
83
84
85 public static final int SDP4 = 3;
86
87
88 public static final int SGP8 = 4;
89
90
91 public static final int SDP8 = 5;
92
93
94 public static final String B_STAR = "BSTAR";
95
96
97 private static final double EPSILON_DEFAULT = 1.0e-10;
98
99
100 private static final int MAX_ITERATIONS_DEFAULT = 100;
101
102
103
104
105
106
107
108 private static final double B_STAR_SCALE = FastMath.scalb(1.0, -20);
109
110
111 private static final String MEAN_MOTION = "meanMotion";
112
113
114 private static final String INCLINATION = "inclination";
115
116
117 private static final String ECCENTRICITY = "eccentricity";
118
119
120 private static final DecimalFormatSymbols SYMBOLS =
121 new DecimalFormatSymbols(Locale.US);
122
123
124 private static final long serialVersionUID = -1596648022319057689L;
125
126
127 private final int satelliteNumber;
128
129
130 private final char classification;
131
132
133 private final int launchYear;
134
135
136 private final int launchNumber;
137
138
139 private final String launchPiece;
140
141
142 private final int ephemerisType;
143
144
145 private final int elementNumber;
146
147
148 private final transient FieldAbsoluteDate<T> epoch;
149
150
151 private final T meanMotion;
152
153
154 private final T meanMotionFirstDerivative;
155
156
157 private final T meanMotionSecondDerivative;
158
159
160 private final T eccentricity;
161
162
163 private final T inclination;
164
165
166 private final T pa;
167
168
169 private final T raan;
170
171
172 private final T meanAnomaly;
173
174
175 private final int revolutionNumberAtEpoch;
176
177
178 private String line1;
179
180
181 private String line2;
182
183
184 private final TimeScale utc;
185
186
187 private final transient ParameterDriver bStarParameterDriver;
188
189
190
191
192
193
194
195
196
197
198
199 @DefaultDataContext
200 public FieldTLE(final Field<T> field, final String line1, final String line2) {
201 this(field, line1, line2, DataContext.getDefault().getTimeScales().getUTC());
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215 public FieldTLE(final Field<T> field, final String line1, final String line2, final TimeScale utc) {
216
217
218 final T zero = field.getZero();
219 final T pi = zero.getPi();
220
221
222 satelliteNumber = ParseUtils.parseSatelliteNumber(line1, 2, 5);
223 final int satNum2 = ParseUtils.parseSatelliteNumber(line2, 2, 5);
224 if (satelliteNumber != satNum2) {
225 throw new OrekitException(OrekitMessages.TLE_LINES_DO_NOT_REFER_TO_SAME_OBJECT,
226 line1, line2);
227 }
228 classification = line1.charAt(7);
229 launchYear = ParseUtils.parseYear(line1, 9);
230 launchNumber = ParseUtils.parseInteger(line1, 11, 3);
231 launchPiece = line1.substring(14, 17).trim();
232 ephemerisType = ParseUtils.parseInteger(line1, 62, 1);
233 elementNumber = ParseUtils.parseInteger(line1, 64, 4);
234
235
236 final int year = ParseUtils.parseYear(line1, 18);
237 final int dayInYear = ParseUtils.parseInteger(line1, 20, 3);
238 final long df = 27l * ParseUtils.parseInteger(line1, 24, 8);
239 final int secondsA = (int) (df / 31250l);
240 final double secondsB = (df % 31250l) / 31250.0;
241 epoch = new FieldAbsoluteDate<>(field, new DateComponents(year, dayInYear),
242 new TimeComponents(secondsA, secondsB),
243 utc);
244
245
246
247 meanMotion = pi.multiply(ParseUtils.parseDouble(line2, 52, 11)).divide(43200.0);
248 meanMotionFirstDerivative = pi.multiply(ParseUtils.parseDouble(line1, 33, 10)).divide(1.86624e9);
249 meanMotionSecondDerivative = pi.multiply(Double.parseDouble((line1.substring(44, 45) + '.' +
250 line1.substring(45, 50) + 'e' +
251 line1.substring(50, 52)).replace(' ', '0'))).divide(5.3747712e13);
252
253 eccentricity = zero.add(Double.parseDouble("." + line2.substring(26, 33).replace(' ', '0')));
254 inclination = zero.add(FastMath.toRadians(ParseUtils.parseDouble(line2, 8, 8)));
255 pa = zero.add(FastMath.toRadians(ParseUtils.parseDouble(line2, 34, 8)));
256 raan = zero.add(FastMath.toRadians(Double.parseDouble(line2.substring(17, 25).replace(' ', '0'))));
257 meanAnomaly = zero.add(FastMath.toRadians(ParseUtils.parseDouble(line2, 43, 8)));
258
259 revolutionNumberAtEpoch = ParseUtils.parseInteger(line2, 63, 5);
260 final double bStarValue = Double.parseDouble((line1.substring(53, 54) + '.' +
261 line1.substring(54, 59) + 'e' +
262 line1.substring(59, 61)).replace(' ', '0'));
263
264
265 this.line1 = line1;
266 this.line2 = line2;
267 this.utc = utc;
268
269 this.bStarParameterDriver = new ParameterDriver(B_STAR, bStarValue, B_STAR_SCALE,
270 Double.NEGATIVE_INFINITY,
271 Double.POSITIVE_INFINITY);
272
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317 @DefaultDataContext
318 public FieldTLE(final int satelliteNumber, final char classification,
319 final int launchYear, final int launchNumber, final String launchPiece,
320 final int ephemerisType, final int elementNumber, final FieldAbsoluteDate<T> epoch,
321 final T meanMotion, final T meanMotionFirstDerivative,
322 final T meanMotionSecondDerivative, final T e, final T i,
323 final T pa, final T raan, final T meanAnomaly,
324 final int revolutionNumberAtEpoch, final double bStar) {
325 this(satelliteNumber, classification, launchYear, launchNumber, launchPiece,
326 ephemerisType, elementNumber, epoch, meanMotion,
327 meanMotionFirstDerivative, meanMotionSecondDerivative, e, i, pa, raan,
328 meanAnomaly, revolutionNumberAtEpoch, bStar,
329 DataContext.getDefault().getTimeScales().getUTC());
330 }
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 public FieldTLE(final int satelliteNumber, final char classification,
373 final int launchYear, final int launchNumber, final String launchPiece,
374 final int ephemerisType, final int elementNumber, final FieldAbsoluteDate<T> epoch,
375 final T meanMotion, final T meanMotionFirstDerivative,
376 final T meanMotionSecondDerivative, final T e, final T i,
377 final T pa, final T raan, final T meanAnomaly,
378 final int revolutionNumberAtEpoch, final double bStar,
379 final TimeScale utc) {
380
381
382 final T pi = e.getPi();
383
384
385 this.satelliteNumber = satelliteNumber;
386 this.classification = classification;
387 this.launchYear = launchYear;
388 this.launchNumber = launchNumber;
389 this.launchPiece = launchPiece;
390 this.ephemerisType = ephemerisType;
391 this.elementNumber = elementNumber;
392
393
394 this.epoch = epoch;
395
396 this.meanMotion = meanMotion;
397 this.meanMotionFirstDerivative = meanMotionFirstDerivative;
398 this.meanMotionSecondDerivative = meanMotionSecondDerivative;
399
400
401 this.inclination = i;
402
403
404 this.raan = MathUtils.normalizeAngle(raan, pi);
405
406
407 this.eccentricity = e;
408
409
410 this.pa = MathUtils.normalizeAngle(pa, pi);
411
412
413 this.meanAnomaly = MathUtils.normalizeAngle(meanAnomaly, pi);
414
415 this.revolutionNumberAtEpoch = revolutionNumberAtEpoch;
416 this.bStarParameterDriver = new ParameterDriver(B_STAR, bStar, B_STAR_SCALE,
417 Double.NEGATIVE_INFINITY,
418 Double.POSITIVE_INFINITY);
419
420
421 this.line1 = null;
422 this.line2 = null;
423 this.utc = utc;
424
425 }
426
427
428
429
430
431
432 TimeScale getUtc() {
433 return utc;
434 }
435
436
437
438
439 public String getLine1() {
440 if (line1 == null) {
441 buildLine1();
442 }
443 return line1;
444 }
445
446
447
448
449 public String getLine2() {
450 if (line2 == null) {
451 buildLine2();
452 }
453 return line2;
454 }
455
456
457
458 private void buildLine1() {
459
460 final StringBuffer buffer = new StringBuffer();
461
462 buffer.append('1');
463
464 buffer.append(' ');
465 buffer.append(ParseUtils.buildSatelliteNumber(satelliteNumber, "satelliteNumber-1"));
466 buffer.append(classification);
467
468 buffer.append(' ');
469 buffer.append(ParseUtils.addPadding("launchYear", launchYear % 100, '0', 2, true, satelliteNumber));
470 buffer.append(ParseUtils.addPadding("launchNumber", launchNumber, '0', 3, true, satelliteNumber));
471 buffer.append(ParseUtils.addPadding("launchPiece", launchPiece, ' ', 3, false, satelliteNumber));
472
473 buffer.append(' ');
474 final DateTimeComponents dtc = epoch.getComponents(utc);
475 buffer.append(ParseUtils.addPadding("year", dtc.getDate().getYear() % 100, '0', 2, true, satelliteNumber));
476 buffer.append(ParseUtils.addPadding("day", dtc.getDate().getDayOfYear(), '0', 3, true, satelliteNumber));
477 buffer.append('.');
478
479 final int fraction = (int) FastMath.rint(31250 * dtc.getTime().getSecondsInUTCDay() / 27.0);
480 buffer.append(ParseUtils.addPadding("fraction", fraction, '0', 8, true, satelliteNumber));
481
482 buffer.append(' ');
483 final double n1 = meanMotionFirstDerivative.divide(pa.getPi()).multiply(1.86624e9).getReal();
484 final String sn1 = ParseUtils.addPadding("meanMotionFirstDerivative",
485 new DecimalFormat(".00000000", SYMBOLS).format(n1),
486 ' ', 10, true, satelliteNumber);
487 buffer.append(sn1);
488
489 buffer.append(' ');
490 final double n2 = meanMotionSecondDerivative.divide(pa.getPi()).multiply(5.3747712e13).getReal();
491 buffer.append(formatExponentMarkerFree("meanMotionSecondDerivative", n2, 5, ' ', 8, true));
492
493 buffer.append(' ');
494 buffer.append(formatExponentMarkerFree("B*", getBStar(), 5, ' ', 8, true));
495
496 buffer.append(' ');
497 buffer.append(ephemerisType);
498
499 buffer.append(' ');
500 buffer.append(ParseUtils.addPadding("elementNumber", elementNumber, ' ', 4, true, satelliteNumber));
501
502 buffer.append(Integer.toString(checksum(buffer)));
503
504 line1 = buffer.toString();
505
506 }
507
508
509
510
511
512
513
514
515
516
517
518 private String formatExponentMarkerFree(final String name, final double d, final int mantissaSize,
519 final char c, final int size, final boolean rightJustified) {
520 final double dAbs = FastMath.abs(d);
521 int exponent = (dAbs < 1.0e-9) ? -9 : (int) FastMath.ceil(FastMath.log10(dAbs));
522 long mantissa = FastMath.round(dAbs * FastMath.pow(10.0, mantissaSize - exponent));
523 if (mantissa == 0) {
524 exponent = 0;
525 } else if (mantissa > (ArithmeticUtils.pow(10, mantissaSize) - 1)) {
526
527
528
529 exponent++;
530 mantissa = FastMath.round(dAbs * FastMath.pow(10.0, mantissaSize - exponent));
531 }
532 final String sMantissa = ParseUtils.addPadding(name, (int) mantissa,
533 '0', mantissaSize, true, satelliteNumber);
534 final String sExponent = Integer.toString(FastMath.abs(exponent));
535 final String formatted = (d < 0 ? '-' : ' ') + sMantissa + (exponent <= 0 ? '-' : '+') + sExponent;
536
537 return ParseUtils.addPadding(name, formatted, c, size, rightJustified, satelliteNumber);
538
539 }
540
541
542
543 private void buildLine2() {
544
545 final StringBuffer buffer = new StringBuffer();
546 final DecimalFormat f34 = new DecimalFormat("##0.0000", SYMBOLS);
547 final DecimalFormat f211 = new DecimalFormat("#0.00000000", SYMBOLS);
548
549 buffer.append('2');
550
551 buffer.append(' ');
552 buffer.append(ParseUtils.buildSatelliteNumber(satelliteNumber, "satelliteNumber-2"));
553
554 buffer.append(' ');
555 buffer.append(ParseUtils.addPadding(INCLINATION, f34.format(FastMath.toDegrees(inclination).getReal()), ' ', 8, true, satelliteNumber));
556 buffer.append(' ');
557 buffer.append(ParseUtils.addPadding("raan", f34.format(FastMath.toDegrees(raan).getReal()), ' ', 8, true, satelliteNumber));
558 buffer.append(' ');
559 buffer.append(ParseUtils.addPadding(ECCENTRICITY, (int) FastMath.rint(eccentricity.getReal() * 1.0e7), '0', 7, true, satelliteNumber));
560 buffer.append(' ');
561 buffer.append(ParseUtils.addPadding("pa", f34.format(FastMath.toDegrees(pa).getReal()), ' ', 8, true, satelliteNumber));
562 buffer.append(' ');
563 buffer.append(ParseUtils.addPadding("meanAnomaly", f34.format(FastMath.toDegrees(meanAnomaly).getReal()), ' ', 8, true, satelliteNumber));
564
565 buffer.append(' ');
566 buffer.append(ParseUtils.addPadding(MEAN_MOTION, f211.format(meanMotion.divide(pa.getPi()).multiply(43200.0).getReal()), ' ', 11, true, satelliteNumber));
567 buffer.append(ParseUtils.addPadding("revolutionNumberAtEpoch", revolutionNumberAtEpoch,
568 ' ', 5, true, satelliteNumber));
569
570 buffer.append(Integer.toString(checksum(buffer)));
571
572 line2 = buffer.toString();
573
574 }
575
576
577
578
579 public List<ParameterDriver> getParametersDrivers() {
580 return Collections.singletonList(bStarParameterDriver);
581 }
582
583
584
585
586
587 public T[] getParameters(final Field<T> field) {
588 final List<ParameterDriver> drivers = getParametersDrivers();
589 final T[] parameters = MathArrays.buildArray(field, drivers.size());
590 int i = 0;
591 for (ParameterDriver driver : drivers) {
592 parameters[i++] = field.getZero().add(driver.getValue());
593 }
594 return parameters;
595 }
596
597
598
599
600 public int getSatelliteNumber() {
601 return satelliteNumber;
602 }
603
604
605
606
607 public char getClassification() {
608 return classification;
609 }
610
611
612
613
614 public int getLaunchYear() {
615 return launchYear;
616 }
617
618
619
620
621 public int getLaunchNumber() {
622 return launchNumber;
623 }
624
625
626
627
628 public String getLaunchPiece() {
629 return launchPiece;
630 }
631
632
633
634
635
636 public int getEphemerisType() {
637 return ephemerisType;
638 }
639
640
641
642
643 public int getElementNumber() {
644 return elementNumber;
645 }
646
647
648
649
650 public FieldAbsoluteDate<T> getDate() {
651 return epoch;
652 }
653
654
655
656
657 public T getMeanMotion() {
658 return meanMotion;
659 }
660
661
662
663
664 public T getMeanMotionFirstDerivative() {
665 return meanMotionFirstDerivative;
666 }
667
668
669
670
671 public T getMeanMotionSecondDerivative() {
672 return meanMotionSecondDerivative;
673 }
674
675
676
677
678 public T getE() {
679 return eccentricity;
680 }
681
682
683
684
685 public T getI() {
686 return inclination;
687 }
688
689
690
691
692 public T getPerigeeArgument() {
693 return pa;
694 }
695
696
697
698
699 public T getRaan() {
700 return raan;
701 }
702
703
704
705
706 public T getMeanAnomaly() {
707 return meanAnomaly;
708 }
709
710
711
712
713 public int getRevolutionNumberAtEpoch() {
714 return revolutionNumberAtEpoch;
715 }
716
717
718
719
720 public double getBStar() {
721 return bStarParameterDriver.getValue();
722 }
723
724
725
726
727
728
729 public String toString() {
730 try {
731 return getLine1() + System.getProperty("line.separator") + getLine2();
732 } catch (OrekitException oe) {
733 throw new OrekitInternalError(oe);
734 }
735 }
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755 @DefaultDataContext
756 public static <T extends CalculusFieldElement<T>> FieldTLE<T> stateToTLE(final FieldSpacecraftState<T> state, final FieldTLE<T> templateTLE) {
757 return stateToTLE(state, templateTLE,
758 DataContext.getDefault().getTimeScales().getUTC(),
759 DataContext.getDefault().getFrames().getTEME());
760 }
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781 public static <T extends CalculusFieldElement<T>> FieldTLE<T> stateToTLE(final FieldSpacecraftState<T> state, final FieldTLE<T> templateTLE,
782 final TimeScale utc, final Frame teme) {
783 return stateToTLE(state, templateTLE, utc, teme, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
784 }
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802 public static <T extends CalculusFieldElement<T>> FieldTLE<T> stateToTLE(final FieldSpacecraftState<T> state, final FieldTLE<T> templateTLE,
803 final TimeScale utc, final Frame teme,
804 final double epsilon, final int maxIterations) {
805
806
807 final FieldEquinoctialOrbit<T> equiOrbit = convert(state.getOrbit(), teme);
808 T sma = equiOrbit.getA();
809 T ex = equiOrbit.getEquinoctialEx();
810 T ey = equiOrbit.getEquinoctialEy();
811 T hx = equiOrbit.getHx();
812 T hy = equiOrbit.getHy();
813 T lv = equiOrbit.getLv();
814
815
816 final FieldKeplerianOrbit<T> keplerianOrbit = (FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(equiOrbit);
817 FieldTLE<T> current = newTLE(keplerianOrbit, templateTLE, utc);
818
819
820 final Field<T> field = state.getDate().getField();
821
822
823 final T thrA = sma.add(1).multiply(epsilon);
824 final T thrE = FastMath.hypot(ex, ey).add(1).multiply(epsilon);
825 final T thrH = FastMath.hypot(hx, hy).add(1).multiply(epsilon);
826 final T thrV = sma.getPi().multiply(epsilon);
827
828 int k = 0;
829 while (k++ < maxIterations) {
830
831
832 final FieldTLEPropagator<T> propagator = FieldTLEPropagator.selectExtrapolator(current, new InertialProvider(Rotation.IDENTITY, teme), state.getMass(), teme, templateTLE.getParameters(field));
833 final FieldOrbit<T> recovOrbit = propagator.getInitialState().getOrbit();
834 final FieldEquinoctialOrbit<T> recovEquiOrbit = (FieldEquinoctialOrbit<T>) OrbitType.EQUINOCTIAL.convertType(recovOrbit);
835
836
837 final T deltaSma = equiOrbit.getA().subtract(recovEquiOrbit.getA());
838 final T deltaEx = equiOrbit.getEquinoctialEx().subtract(recovEquiOrbit.getEquinoctialEx());
839 final T deltaEy = equiOrbit.getEquinoctialEy().subtract(recovEquiOrbit.getEquinoctialEy());
840 final T deltaHx = equiOrbit.getHx().subtract(recovEquiOrbit.getHx());
841 final T deltaHy = equiOrbit.getHy().subtract(recovEquiOrbit.getHy());
842 final T deltaLv = MathUtils.normalizeAngle(equiOrbit.getLv().subtract(recovEquiOrbit.getLv()), field.getZero());
843
844
845 if (FastMath.abs(deltaSma.getReal()) < thrA.getReal() &&
846 FastMath.abs(deltaEx.getReal()) < thrE.getReal() &&
847 FastMath.abs(deltaEy.getReal()) < thrE.getReal() &&
848 FastMath.abs(deltaHx.getReal()) < thrH.getReal() &&
849 FastMath.abs(deltaHy.getReal()) < thrH.getReal() &&
850 FastMath.abs(deltaLv.getReal()) < thrV.getReal()) {
851
852 return current;
853 }
854
855
856 sma = sma.add(deltaSma);
857 ex = ex.add(deltaEx);
858 ey = ey.add(deltaEy);
859 hx = hx.add(deltaHx);
860 hy = hy.add(deltaHy);
861 lv = lv.add(deltaLv);
862 final FieldEquinoctialOrbit<T> newEquiOrbit =
863 new FieldEquinoctialOrbit<>(sma, ex, ey, hx, hy, lv, PositionAngle.TRUE,
864 equiOrbit.getFrame(), equiOrbit.getDate(), equiOrbit.getMu());
865 final FieldKeplerianOrbit<T> newKeplOrbit = (FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(newEquiOrbit);
866
867
868 current = newTLE(newKeplOrbit, templateTLE, utc);
869 }
870
871 throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_TLE, k);
872 }
873
874
875
876
877
878
879
880
881
882 private static <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> convert(final FieldOrbit<T> orbitIn, final Frame teme) {
883 return new FieldEquinoctialOrbit<T>(orbitIn.getPVCoordinates(teme), teme, orbitIn.getMu());
884 }
885
886
887
888
889
890
891
892
893
894 private static <T extends CalculusFieldElement<T>> FieldTLE<T> newTLE(final FieldKeplerianOrbit<T> keplerianOrbit, final FieldTLE<T> templateTLE,
895 final TimeScale utc) {
896
897 final T meanMotion = keplerianOrbit.getKeplerianMeanMotion();
898 final T e = keplerianOrbit.getE();
899 final T i = keplerianOrbit.getI();
900 final T raan = keplerianOrbit.getRightAscensionOfAscendingNode();
901 final T pa = keplerianOrbit.getPerigeeArgument();
902 final T meanAnomaly = keplerianOrbit.getMeanAnomaly();
903
904 final FieldAbsoluteDate<T> epoch = keplerianOrbit.getDate();
905
906 final int satelliteNumber = templateTLE.getSatelliteNumber();
907 final char classification = templateTLE.getClassification();
908 final int launchYear = templateTLE.getLaunchYear();
909 final int launchNumber = templateTLE.getLaunchNumber();
910 final String launchPiece = templateTLE.getLaunchPiece();
911 final int ephemerisType = templateTLE.getEphemerisType();
912 final int elementNumber = templateTLE.getElementNumber();
913
914 final int revolutionNumberAtEpoch = templateTLE.getRevolutionNumberAtEpoch();
915 final T dt = epoch.durationFrom(templateTLE.getDate());
916 final int newRevolutionNumberAtEpoch = (int) ((int) revolutionNumberAtEpoch + FastMath.floor(MathUtils.normalizeAngle(meanAnomaly, e.getPi()).add(dt.multiply(meanMotion)).divide(e.getPi().multiply(2.0))).getReal());
917
918 final double bStar = templateTLE.getBStar();
919
920 final T meanMotionFirstDerivative = templateTLE.getMeanMotionFirstDerivative();
921 final T meanMotionSecondDerivative = templateTLE.getMeanMotionSecondDerivative();
922
923 return new FieldTLE<>(satelliteNumber, classification, launchYear, launchNumber, launchPiece, ephemerisType,
924 elementNumber, epoch, meanMotion, meanMotionFirstDerivative, meanMotionSecondDerivative,
925 e, i, pa, raan, meanAnomaly, newRevolutionNumberAtEpoch, bStar, utc);
926 }
927
928
929
930
931
932
933
934
935 public static boolean isFormatOK(final String line1, final String line2) {
936 return TLE.isFormatOK(line1, line2);
937 }
938
939
940
941
942
943 private static int checksum(final CharSequence line) {
944 int sum = 0;
945 for (int j = 0; j < 68; j++) {
946 final char c = line.charAt(j);
947 if (Character.isDigit(c)) {
948 sum += Character.digit(c, 10);
949 } else if (c == '-') {
950 ++sum;
951 }
952 }
953 return sum % 10;
954 }
955
956
957
958
959
960 public TLE toTLE() {
961 final TLE regularTLE = new TLE(getSatelliteNumber(), getClassification(), getLaunchYear(), getLaunchNumber(), getLaunchPiece(), getEphemerisType(),
962 getElementNumber(), getDate().toAbsoluteDate(), getMeanMotion().getReal(), getMeanMotionFirstDerivative().getReal(),
963 getMeanMotionSecondDerivative().getReal(), getE().getReal(), getI().getReal(), getPerigeeArgument().getReal(),
964 getRaan().getReal(), getMeanAnomaly().getReal(), getRevolutionNumberAtEpoch(), getBStar(), getUtc());
965
966 for (int k = 0; k < regularTLE.getParametersDrivers().size(); ++k) {
967 regularTLE.getParametersDrivers().get(k).setSelected(getParametersDrivers().get(k).isSelected());
968 }
969
970 return regularTLE;
971
972 }
973
974
975
976
977
978
979
980
981
982 @Override
983 public boolean equals(final Object o) {
984 if (o == this) {
985 return true;
986 }
987 if (!(o instanceof FieldTLE)) {
988 return false;
989 }
990 @SuppressWarnings("unchecked")
991 final FieldTLE<T> tle = (FieldTLE<T>) o;
992 return satelliteNumber == tle.satelliteNumber &&
993 classification == tle.classification &&
994 launchYear == tle.launchYear &&
995 launchNumber == tle.launchNumber &&
996 Objects.equals(launchPiece, tle.launchPiece) &&
997 ephemerisType == tle.ephemerisType &&
998 elementNumber == tle.elementNumber &&
999 Objects.equals(epoch, tle.epoch) &&
1000 meanMotion.getReal() == tle.meanMotion.getReal() &&
1001 meanMotionFirstDerivative.getReal() == tle.meanMotionFirstDerivative.getReal() &&
1002 meanMotionSecondDerivative.getReal() == tle.meanMotionSecondDerivative.getReal() &&
1003 eccentricity.getReal() == tle.eccentricity.getReal() &&
1004 inclination.getReal() == tle.inclination.getReal() &&
1005 pa.getReal() == tle.pa.getReal() &&
1006 raan.getReal() == tle.raan.getReal() &&
1007 meanAnomaly.getReal() == tle.meanAnomaly.getReal() &&
1008 revolutionNumberAtEpoch == tle.revolutionNumberAtEpoch &&
1009 getBStar() == tle.getBStar();
1010 }
1011
1012
1013
1014
1015 @Override
1016 public int hashCode() {
1017 return Objects.hash(satelliteNumber,
1018 classification,
1019 launchYear,
1020 launchNumber,
1021 launchPiece,
1022 ephemerisType,
1023 elementNumber,
1024 epoch,
1025 meanMotion,
1026 meanMotionFirstDerivative,
1027 meanMotionSecondDerivative,
1028 eccentricity,
1029 inclination,
1030 pa,
1031 raan,
1032 meanAnomaly,
1033 revolutionNumberAtEpoch,
1034 getBStar());
1035 }
1036
1037 }