ootk 6.0.1 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs CHANGED
@@ -9857,13 +9857,26 @@ var FormatTle = class _FormatTle {
9857
9857
  const meanaStr = _FormatTle.meanAnomaly(meana);
9858
9858
  const ecenStr = _FormatTle.eccentricity(ecen);
9859
9859
  const intlStr = intl.padEnd(8, " ");
9860
- let TLE1Ending = tleParams.sat ? tleParams.sat.tle1.substring(32, 71) : " +.00000000 +00000+0 +00000-0 0 9990";
9860
+ const classification = tleParams.classification ?? "U";
9861
+ const elementSetNo = (tleParams.elementSetNo ?? 999).toString().padStart(4, " ");
9862
+ const ephemerisType = (tleParams.ephemerisType ?? 0).toString();
9863
+ const revAtEpoch = (tleParams.revAtEpoch ?? 0).toString().padStart(5, " ");
9864
+ let TLE1Ending;
9865
+ if (tleParams.sat) {
9866
+ TLE1Ending = tleParams.sat.tle1.substring(32, 71);
9867
+ } else {
9868
+ const mmDot = _FormatTle.formatMeanMotionDot(tleParams.meanMotionDot ?? 0);
9869
+ const mmDdot = _FormatTle.formatTleExponential(tleParams.meanMotionDdot ?? 0);
9870
+ const bstarStr = _FormatTle.formatTleExponential(tleParams.bstar ?? 0);
9871
+ TLE1Ending = ` ${mmDot} ${mmDdot} ${bstarStr} ${ephemerisType} ${elementSetNo}0`;
9872
+ }
9861
9873
  TLE1Ending = TLE1Ending[1] === " " ? _FormatTle.setCharAt(TLE1Ending, 1, "+") : TLE1Ending;
9862
9874
  TLE1Ending = TLE1Ending[12] === " " ? _FormatTle.setCharAt(TLE1Ending, 12, "+") : TLE1Ending;
9863
9875
  TLE1Ending = TLE1Ending[21] === " " ? _FormatTle.setCharAt(TLE1Ending, 21, "+") : TLE1Ending;
9864
- TLE1Ending = TLE1Ending[32] === " " ? _FormatTle.setCharAt(TLE1Ending, 32, "0") : TLE1Ending;
9865
- const tle1 = `1 ${scc}U ${intlStr} ${epochYrStr}${epochdayStr}${TLE1Ending}`;
9866
- const tle2 = `2 ${scc} ${incStr} ${rascStr} ${ecenStr} ${argPeStr} ${meanaStr} ${meanmoStr} 00010`;
9876
+ const tle1Pre = `1 ${scc}${classification} ${intlStr} ${epochYrStr}${epochdayStr}${TLE1Ending}`;
9877
+ const tle1 = _FormatTle.setCharAt(tle1Pre, 68, _FormatTle.tleChecksum(tle1Pre).toString());
9878
+ const tle2Pre = `2 ${scc} ${incStr} ${rascStr} ${ecenStr} ${argPeStr} ${meanaStr} ${meanmoStr}${revAtEpoch}0`;
9879
+ const tle2 = _FormatTle.setCharAt(tle2Pre, 68, _FormatTle.tleChecksum(tle2Pre).toString());
9867
9880
  return { tle1, tle2 };
9868
9881
  }
9869
9882
  /**
@@ -9992,6 +10005,61 @@ var FormatTle = class _FormatTle {
9992
10005
  }
9993
10006
  return `${str.substring(0, index)}${chr}${str.substring(index + 1)}`;
9994
10007
  }
10008
+ /**
10009
+ * Format mean motion dot (first derivative / 2) for TLE line 1.
10010
+ * Format: sign + ".NNNNNNNN" = 10 chars total.
10011
+ * @param value - Mean motion dot value (rev/day^2)
10012
+ * @returns Formatted 10-character string
10013
+ */
10014
+ static formatMeanMotionDot(value) {
10015
+ const sign2 = value >= 0 ? " " : "-";
10016
+ return sign2 + Math.abs(value).toFixed(8).substring(1);
10017
+ }
10018
+ /**
10019
+ * Format a value in TLE exponential notation for BSTAR or mean motion ddot.
10020
+ * Format: "sNNNNN±N" (8 chars) where mantissa has implied leading decimal point.
10021
+ * Example: 0.00017507 → " 17507-3" (i.e., .17507 × 10^-3)
10022
+ * @param value - The value to format
10023
+ * @returns Formatted 8-character string
10024
+ */
10025
+ static formatTleExponential(value) {
10026
+ if (value === 0) {
10027
+ return " 00000-0";
10028
+ }
10029
+ const sign2 = value >= 0 ? " " : "-";
10030
+ const absVal = Math.abs(value);
10031
+ let exponent = Math.floor(Math.log10(absVal)) + 1;
10032
+ let mantissa = absVal / Math.pow(10, exponent);
10033
+ if (mantissa >= 1) {
10034
+ mantissa /= 10;
10035
+ exponent++;
10036
+ }
10037
+ if (mantissa < 0.1 && mantissa > 0) {
10038
+ mantissa *= 10;
10039
+ exponent--;
10040
+ }
10041
+ const mantissaStr = Math.round(mantissa * 1e5).toString().padStart(5, "0");
10042
+ const expSign = exponent >= 0 ? "+" : "-";
10043
+ const expStr = Math.abs(exponent).toString();
10044
+ return sign2 + mantissaStr + expSign + expStr;
10045
+ }
10046
+ /**
10047
+ * Compute TLE line checksum (modulo 10 sum of digits, '-' counts as 1).
10048
+ * @param line - TLE line (first 68 characters are summed)
10049
+ * @returns Checksum digit (0-9)
10050
+ */
10051
+ static tleChecksum(line) {
10052
+ let sum = 0;
10053
+ for (let i = 0; i < 68 && i < line.length; i++) {
10054
+ const c = line[i];
10055
+ if (c >= "0" && c <= "9") {
10056
+ sum += parseInt(c);
10057
+ } else if (c === "-") {
10058
+ sum += 1;
10059
+ }
10060
+ }
10061
+ return sum % 10;
10062
+ }
9995
10063
  };
9996
10064
 
9997
10065
  // src/coordinate/RelativeState.ts
@@ -16625,8 +16693,9 @@ var Satellite = class _Satellite extends SpaceObject {
16625
16693
  this.satrec = Sgp4.createSatrec(tle1, tle2);
16626
16694
  }
16627
16695
  parseOmmAndUpdateOrbit_(omm) {
16628
- this.sccNum = omm.NORAD_CAT_ID.padStart(5, "0");
16629
- this.sccNum5 = Tle.convert6DigitToA5(omm.NORAD_CAT_ID);
16696
+ const noradStr = String(omm.NORAD_CAT_ID);
16697
+ this.sccNum = noradStr.padStart(5, "0");
16698
+ this.sccNum5 = Tle.convert6DigitToA5(noradStr);
16630
16699
  this.sccNum6 = Tle.convertA5to6Digit(this.sccNum5);
16631
16700
  this.intlDes = omm.OBJECT_ID;
16632
16701
  const YYYY = omm.EPOCH.slice(0, 4);
@@ -16639,6 +16708,19 @@ var Satellite = class _Satellite extends SpaceObject {
16639
16708
  const dayOfYear = (epochDateObj - Date.UTC(Number(YYYY), 0, 0)) / 864e5;
16640
16709
  const ommParsed = {
16641
16710
  ...omm,
16711
+ NORAD_CAT_ID: noradStr,
16712
+ MEAN_MOTION: String(omm.MEAN_MOTION),
16713
+ ECCENTRICITY: String(omm.ECCENTRICITY),
16714
+ INCLINATION: String(omm.INCLINATION),
16715
+ RA_OF_ASC_NODE: String(omm.RA_OF_ASC_NODE),
16716
+ ARG_OF_PERICENTER: String(omm.ARG_OF_PERICENTER),
16717
+ MEAN_ANOMALY: String(omm.MEAN_ANOMALY),
16718
+ EPHEMERIS_TYPE: String(omm.EPHEMERIS_TYPE),
16719
+ ELEMENT_SET_NO: String(omm.ELEMENT_SET_NO),
16720
+ REV_AT_EPOCH: String(omm.REV_AT_EPOCH),
16721
+ BSTAR: String(omm.BSTAR),
16722
+ MEAN_MOTION_DOT: String(omm.MEAN_MOTION_DOT),
16723
+ MEAN_MOTION_DDOT: String(omm.MEAN_MOTION_DDOT),
16642
16724
  epoch: {
16643
16725
  year: Number(YYYY),
16644
16726
  month: Number(MM),
@@ -16651,20 +16733,41 @@ var Satellite = class _Satellite extends SpaceObject {
16651
16733
  };
16652
16734
  this.epochYear = parseInt(YYYY.slice(2, 4));
16653
16735
  this.epochDay = dayOfYear;
16654
- this.meanMoDev1 = parseFloat(omm.MEAN_MOTION_DOT);
16655
- this.meanMoDev2 = parseFloat(omm.MEAN_MOTION_DDOT);
16656
- this.bstar = parseFloat(omm.BSTAR);
16657
- this.inclination = parseFloat(omm.INCLINATION);
16658
- this.rightAscension = parseFloat(omm.RA_OF_ASC_NODE);
16659
- this.eccentricity = parseFloat(omm.ECCENTRICITY);
16660
- this.argOfPerigee = parseFloat(omm.ARG_OF_PERICENTER);
16661
- this.meanAnomaly = parseFloat(omm.MEAN_ANOMALY);
16662
- this.meanMotion = parseFloat(omm.MEAN_MOTION);
16736
+ this.meanMoDev1 = Number(omm.MEAN_MOTION_DOT);
16737
+ this.meanMoDev2 = Number(omm.MEAN_MOTION_DDOT);
16738
+ this.bstar = Number(omm.BSTAR);
16739
+ this.inclination = Number(omm.INCLINATION);
16740
+ this.rightAscension = Number(omm.RA_OF_ASC_NODE);
16741
+ this.eccentricity = Number(omm.ECCENTRICITY);
16742
+ this.argOfPerigee = Number(omm.ARG_OF_PERICENTER);
16743
+ this.meanAnomaly = Number(omm.MEAN_ANOMALY);
16744
+ this.meanMotion = Number(omm.MEAN_MOTION);
16663
16745
  this.period = 1440 / this.meanMotion;
16664
16746
  this.semiMajorAxis = (8681663653e-3 / this.meanMotion) ** (2 / 3);
16665
16747
  this.semiMinorAxis = this.semiMajorAxis * Math.sqrt(1 - this.eccentricity ** 2);
16666
16748
  this.apogee = this.semiMajorAxis * (1 + this.eccentricity) - 6371;
16667
16749
  this.perigee = this.semiMajorAxis * (1 - this.eccentricity) - 6371;
16750
+ const { tle1, tle2 } = FormatTle.createTle({
16751
+ inc: this.inclination,
16752
+ meanmo: this.meanMotion,
16753
+ rasc: this.rightAscension,
16754
+ argPe: this.argOfPerigee,
16755
+ meana: this.meanAnomaly,
16756
+ ecen: this.eccentricity,
16757
+ epochyr: this.epochYear,
16758
+ epochday: this.epochDay,
16759
+ intl: omm.OBJECT_ID,
16760
+ scc: this.sccNum,
16761
+ bstar: this.bstar,
16762
+ meanMotionDot: this.meanMoDev1,
16763
+ meanMotionDdot: this.meanMoDev2,
16764
+ classification: String(omm.CLASSIFICATION_TYPE) || "U",
16765
+ revAtEpoch: Number(omm.REV_AT_EPOCH) || 0,
16766
+ elementSetNo: Number(omm.ELEMENT_SET_NO) || 999,
16767
+ ephemerisType: Number(omm.EPHEMERIS_TYPE) || 0
16768
+ });
16769
+ this.tle1 = tle1;
16770
+ this.tle2 = tle2;
16668
16771
  this.satrec = Sgp4.createSatrecFromOmm(ommParsed);
16669
16772
  }
16670
16773
  // ==================== Type Checking ====================
@@ -25180,6 +25283,61 @@ var OmmParser = class _OmmParser {
25180
25283
  const theory = omm.metadata.MEAN_ELEMENT_THEORY.toUpperCase();
25181
25284
  return theory === "SGP" || theory === "SGP4" || theory === "SGP4-XP";
25182
25285
  }
25286
+ /**
25287
+ * Parse a CelesTrak-style flat JSON OMM object into the structured ParsedOmm format.
25288
+ *
25289
+ * CelesTrak's JSON OMM format is a flat object with all fields at the top level,
25290
+ * omitting metadata fields like CENTER_NAME, REF_FRAME, TIME_SYSTEM, and
25291
+ * MEAN_ELEMENT_THEORY (which are always EARTH/TEME/UTC/SGP4 for GP data).
25292
+ *
25293
+ * @param omm - A flat OMM JSON object from CelesTrak
25294
+ * @returns Parsed OMM structure with inferred metadata
25295
+ */
25296
+ static parseJson(omm) {
25297
+ const result = {
25298
+ header: {
25299
+ CCSDS_OMM_VERS: "3.0",
25300
+ CREATION_DATE: (/* @__PURE__ */ new Date()).toISOString(),
25301
+ ORIGINATOR: "CelesTrak"
25302
+ },
25303
+ metadata: {
25304
+ OBJECT_NAME: omm.OBJECT_NAME,
25305
+ OBJECT_ID: omm.OBJECT_ID,
25306
+ CENTER_NAME: "EARTH",
25307
+ REF_FRAME: "TEME",
25308
+ TIME_SYSTEM: "UTC",
25309
+ MEAN_ELEMENT_THEORY: "SGP4"
25310
+ },
25311
+ meanElements: {
25312
+ EPOCH: omm.EPOCH,
25313
+ MEAN_MOTION: Number(omm.MEAN_MOTION),
25314
+ ECCENTRICITY: Number(omm.ECCENTRICITY),
25315
+ INCLINATION: Number(omm.INCLINATION),
25316
+ RA_OF_ASC_NODE: Number(omm.RA_OF_ASC_NODE),
25317
+ ARG_OF_PERICENTER: Number(omm.ARG_OF_PERICENTER),
25318
+ MEAN_ANOMALY: Number(omm.MEAN_ANOMALY)
25319
+ },
25320
+ tleParameters: {
25321
+ EPHEMERIS_TYPE: Number(omm.EPHEMERIS_TYPE),
25322
+ CLASSIFICATION_TYPE: String(omm.CLASSIFICATION_TYPE),
25323
+ NORAD_CAT_ID: Number(omm.NORAD_CAT_ID),
25324
+ ELEMENT_SET_NO: Number(omm.ELEMENT_SET_NO),
25325
+ REV_AT_EPOCH: Number(omm.REV_AT_EPOCH),
25326
+ BSTAR: Number(omm.BSTAR),
25327
+ MEAN_MOTION_DOT: Number(omm.MEAN_MOTION_DOT),
25328
+ MEAN_MOTION_DDOT: Number(omm.MEAN_MOTION_DDOT)
25329
+ }
25330
+ };
25331
+ return result;
25332
+ }
25333
+ /**
25334
+ * Parse an array of CelesTrak-style flat JSON OMM objects.
25335
+ * @param ommArray - Array of flat OMM JSON objects from CelesTrak
25336
+ * @returns Array of parsed OMM structures
25337
+ */
25338
+ static parseJsonArray(ommArray) {
25339
+ return ommArray.map((omm) => _OmmParser.parseJson(omm));
25340
+ }
25183
25341
  /**
25184
25342
  * Parse all key-value pairs from OMM lines (excluding COMMENT lines).
25185
25343
  */
package/dist/main.d.cts CHANGED
@@ -1816,6 +1816,27 @@ declare abstract class FormatTle {
1816
1816
  * @returns The modified string with the character set at the specified index.
1817
1817
  */
1818
1818
  static setCharAt(str: string, index: number, chr: string): string;
1819
+ /**
1820
+ * Format mean motion dot (first derivative / 2) for TLE line 1.
1821
+ * Format: sign + ".NNNNNNNN" = 10 chars total.
1822
+ * @param value - Mean motion dot value (rev/day^2)
1823
+ * @returns Formatted 10-character string
1824
+ */
1825
+ static formatMeanMotionDot(value: number): string;
1826
+ /**
1827
+ * Format a value in TLE exponential notation for BSTAR or mean motion ddot.
1828
+ * Format: "sNNNNN±N" (8 chars) where mantissa has implied leading decimal point.
1829
+ * Example: 0.00017507 → " 17507-3" (i.e., .17507 × 10^-3)
1830
+ * @param value - The value to format
1831
+ * @returns Formatted 8-character string
1832
+ */
1833
+ static formatTleExponential(value: number): string;
1834
+ /**
1835
+ * Compute TLE line checksum (modulo 10 sum of digits, '-' counts as 1).
1836
+ * @param line - TLE line (first 68 characters are summed)
1837
+ * @returns Checksum digit (0-9)
1838
+ */
1839
+ static tleChecksum(line: string): number;
1819
1840
  }
1820
1841
 
1821
1842
  /**
@@ -2780,37 +2801,34 @@ declare class RIC extends RelativeState {
2780
2801
  }
2781
2802
 
2782
2803
  /**
2783
- * Represents the data format for orbital elements as provided by the Omm system.
2784
- * Each property is expressed as a string to accommodate various formatting or precision
2785
- * requirements from the data source.
2804
+ * Represents the data format for orbital elements as provided by the OMM system.
2805
+ * Numeric fields accept both string and number to support CelesTrak's JSON format
2806
+ * (which sends numbers as numbers) and other sources that send them as strings.
2786
2807
  */
2787
2808
  interface OmmDataFormat {
2788
2809
  OBJECT_NAME: string;
2789
2810
  OBJECT_ID: string;
2790
2811
  /** Date in YYYY-MM-DDTHH:MM:SS.SSSSSS UTC format */
2791
2812
  EPOCH: string;
2792
- MEAN_MOTION: string;
2793
- ECCENTRICITY: string;
2794
- INCLINATION: string;
2795
- RA_OF_ASC_NODE: string;
2796
- ARG_OF_PERICENTER: string;
2797
- MEAN_ANOMALY: string;
2798
- EPHEMERIS_TYPE: string;
2813
+ MEAN_MOTION: string | number;
2814
+ ECCENTRICITY: string | number;
2815
+ INCLINATION: string | number;
2816
+ RA_OF_ASC_NODE: string | number;
2817
+ ARG_OF_PERICENTER: string | number;
2818
+ MEAN_ANOMALY: string | number;
2819
+ EPHEMERIS_TYPE: string | number;
2799
2820
  CLASSIFICATION_TYPE: string;
2800
- NORAD_CAT_ID: string;
2801
- ELEMENT_SET_NO: string;
2802
- REV_AT_EPOCH: string;
2803
- BSTAR: string;
2804
- MEAN_MOTION_DOT: string;
2805
- MEAN_MOTION_DDOT: string;
2821
+ NORAD_CAT_ID: string | number;
2822
+ ELEMENT_SET_NO: string | number;
2823
+ REV_AT_EPOCH: string | number;
2824
+ BSTAR: string | number;
2825
+ MEAN_MOTION_DOT: string | number;
2826
+ MEAN_MOTION_DDOT: string | number;
2806
2827
  }
2807
2828
  /**
2808
- * Represents the parsed data format for orbital elements as provided by the Omm system.
2809
- * Each property is expressed as a string to accommodate various formatting or precision
2810
- * requirements from the data source.
2811
- * The `epoch` property is an object that contains the parsed date and time values.
2812
- * The `doy` property is the day of the year.
2813
- * The `epoch` property is an object that contains the parsed date and time values.
2829
+ * Represents the parsed data format for orbital elements as provided by the OMM system.
2830
+ * String fields are preserved from the original data; the `epoch` property contains
2831
+ * the parsed date/time values used for SGP4 initialization.
2814
2832
  */
2815
2833
  interface OmmParsedDataFormat {
2816
2834
  OBJECT_NAME: string;
@@ -5919,6 +5937,20 @@ type TleParams = {
5919
5937
  intl: string;
5920
5938
  /** alpha 5 satellite number */
5921
5939
  scc: string;
5940
+ /** B* drag term (1/Earth radii). Used when `sat` is not provided. */
5941
+ bstar?: number;
5942
+ /** First derivative of mean motion / 2 (rev/day^2). Used when `sat` is not provided. */
5943
+ meanMotionDot?: number;
5944
+ /** Second derivative of mean motion / 6 (rev/day^3). Used when `sat` is not provided. */
5945
+ meanMotionDdot?: number;
5946
+ /** Classification type (default 'U'). Used when `sat` is not provided. */
5947
+ classification?: string;
5948
+ /** Revolution number at epoch. Used when `sat` is not provided. */
5949
+ revAtEpoch?: number;
5950
+ /** Element set number (default 999). Used when `sat` is not provided. */
5951
+ elementSetNo?: number;
5952
+ /** Ephemeris type (default 0). Used when `sat` is not provided. */
5953
+ ephemerisType?: number;
5922
5954
  };
5923
5955
  type PositionVelocity = {
5924
5956
  position: Vector3D<Kilometers>;
@@ -14078,6 +14110,23 @@ declare class OmmParser {
14078
14110
  * @returns true if the OMM uses SGP, SGP4, or SGP4-XP mean element theory
14079
14111
  */
14080
14112
  static isTleCompatible(omm: ParsedOmm): boolean;
14113
+ /**
14114
+ * Parse a CelesTrak-style flat JSON OMM object into the structured ParsedOmm format.
14115
+ *
14116
+ * CelesTrak's JSON OMM format is a flat object with all fields at the top level,
14117
+ * omitting metadata fields like CENTER_NAME, REF_FRAME, TIME_SYSTEM, and
14118
+ * MEAN_ELEMENT_THEORY (which are always EARTH/TEME/UTC/SGP4 for GP data).
14119
+ *
14120
+ * @param omm - A flat OMM JSON object from CelesTrak
14121
+ * @returns Parsed OMM structure with inferred metadata
14122
+ */
14123
+ static parseJson(omm: OmmDataFormat): ParsedOmm;
14124
+ /**
14125
+ * Parse an array of CelesTrak-style flat JSON OMM objects.
14126
+ * @param ommArray - Array of flat OMM JSON objects from CelesTrak
14127
+ * @returns Array of parsed OMM structures
14128
+ */
14129
+ static parseJsonArray(ommArray: OmmDataFormat[]): ParsedOmm[];
14081
14130
  /**
14082
14131
  * Parse all key-value pairs from OMM lines (excluding COMMENT lines).
14083
14132
  */
package/dist/main.d.ts CHANGED
@@ -1816,6 +1816,27 @@ declare abstract class FormatTle {
1816
1816
  * @returns The modified string with the character set at the specified index.
1817
1817
  */
1818
1818
  static setCharAt(str: string, index: number, chr: string): string;
1819
+ /**
1820
+ * Format mean motion dot (first derivative / 2) for TLE line 1.
1821
+ * Format: sign + ".NNNNNNNN" = 10 chars total.
1822
+ * @param value - Mean motion dot value (rev/day^2)
1823
+ * @returns Formatted 10-character string
1824
+ */
1825
+ static formatMeanMotionDot(value: number): string;
1826
+ /**
1827
+ * Format a value in TLE exponential notation for BSTAR or mean motion ddot.
1828
+ * Format: "sNNNNN±N" (8 chars) where mantissa has implied leading decimal point.
1829
+ * Example: 0.00017507 → " 17507-3" (i.e., .17507 × 10^-3)
1830
+ * @param value - The value to format
1831
+ * @returns Formatted 8-character string
1832
+ */
1833
+ static formatTleExponential(value: number): string;
1834
+ /**
1835
+ * Compute TLE line checksum (modulo 10 sum of digits, '-' counts as 1).
1836
+ * @param line - TLE line (first 68 characters are summed)
1837
+ * @returns Checksum digit (0-9)
1838
+ */
1839
+ static tleChecksum(line: string): number;
1819
1840
  }
1820
1841
 
1821
1842
  /**
@@ -2780,37 +2801,34 @@ declare class RIC extends RelativeState {
2780
2801
  }
2781
2802
 
2782
2803
  /**
2783
- * Represents the data format for orbital elements as provided by the Omm system.
2784
- * Each property is expressed as a string to accommodate various formatting or precision
2785
- * requirements from the data source.
2804
+ * Represents the data format for orbital elements as provided by the OMM system.
2805
+ * Numeric fields accept both string and number to support CelesTrak's JSON format
2806
+ * (which sends numbers as numbers) and other sources that send them as strings.
2786
2807
  */
2787
2808
  interface OmmDataFormat {
2788
2809
  OBJECT_NAME: string;
2789
2810
  OBJECT_ID: string;
2790
2811
  /** Date in YYYY-MM-DDTHH:MM:SS.SSSSSS UTC format */
2791
2812
  EPOCH: string;
2792
- MEAN_MOTION: string;
2793
- ECCENTRICITY: string;
2794
- INCLINATION: string;
2795
- RA_OF_ASC_NODE: string;
2796
- ARG_OF_PERICENTER: string;
2797
- MEAN_ANOMALY: string;
2798
- EPHEMERIS_TYPE: string;
2813
+ MEAN_MOTION: string | number;
2814
+ ECCENTRICITY: string | number;
2815
+ INCLINATION: string | number;
2816
+ RA_OF_ASC_NODE: string | number;
2817
+ ARG_OF_PERICENTER: string | number;
2818
+ MEAN_ANOMALY: string | number;
2819
+ EPHEMERIS_TYPE: string | number;
2799
2820
  CLASSIFICATION_TYPE: string;
2800
- NORAD_CAT_ID: string;
2801
- ELEMENT_SET_NO: string;
2802
- REV_AT_EPOCH: string;
2803
- BSTAR: string;
2804
- MEAN_MOTION_DOT: string;
2805
- MEAN_MOTION_DDOT: string;
2821
+ NORAD_CAT_ID: string | number;
2822
+ ELEMENT_SET_NO: string | number;
2823
+ REV_AT_EPOCH: string | number;
2824
+ BSTAR: string | number;
2825
+ MEAN_MOTION_DOT: string | number;
2826
+ MEAN_MOTION_DDOT: string | number;
2806
2827
  }
2807
2828
  /**
2808
- * Represents the parsed data format for orbital elements as provided by the Omm system.
2809
- * Each property is expressed as a string to accommodate various formatting or precision
2810
- * requirements from the data source.
2811
- * The `epoch` property is an object that contains the parsed date and time values.
2812
- * The `doy` property is the day of the year.
2813
- * The `epoch` property is an object that contains the parsed date and time values.
2829
+ * Represents the parsed data format for orbital elements as provided by the OMM system.
2830
+ * String fields are preserved from the original data; the `epoch` property contains
2831
+ * the parsed date/time values used for SGP4 initialization.
2814
2832
  */
2815
2833
  interface OmmParsedDataFormat {
2816
2834
  OBJECT_NAME: string;
@@ -5919,6 +5937,20 @@ type TleParams = {
5919
5937
  intl: string;
5920
5938
  /** alpha 5 satellite number */
5921
5939
  scc: string;
5940
+ /** B* drag term (1/Earth radii). Used when `sat` is not provided. */
5941
+ bstar?: number;
5942
+ /** First derivative of mean motion / 2 (rev/day^2). Used when `sat` is not provided. */
5943
+ meanMotionDot?: number;
5944
+ /** Second derivative of mean motion / 6 (rev/day^3). Used when `sat` is not provided. */
5945
+ meanMotionDdot?: number;
5946
+ /** Classification type (default 'U'). Used when `sat` is not provided. */
5947
+ classification?: string;
5948
+ /** Revolution number at epoch. Used when `sat` is not provided. */
5949
+ revAtEpoch?: number;
5950
+ /** Element set number (default 999). Used when `sat` is not provided. */
5951
+ elementSetNo?: number;
5952
+ /** Ephemeris type (default 0). Used when `sat` is not provided. */
5953
+ ephemerisType?: number;
5922
5954
  };
5923
5955
  type PositionVelocity = {
5924
5956
  position: Vector3D<Kilometers>;
@@ -14078,6 +14110,23 @@ declare class OmmParser {
14078
14110
  * @returns true if the OMM uses SGP, SGP4, or SGP4-XP mean element theory
14079
14111
  */
14080
14112
  static isTleCompatible(omm: ParsedOmm): boolean;
14113
+ /**
14114
+ * Parse a CelesTrak-style flat JSON OMM object into the structured ParsedOmm format.
14115
+ *
14116
+ * CelesTrak's JSON OMM format is a flat object with all fields at the top level,
14117
+ * omitting metadata fields like CENTER_NAME, REF_FRAME, TIME_SYSTEM, and
14118
+ * MEAN_ELEMENT_THEORY (which are always EARTH/TEME/UTC/SGP4 for GP data).
14119
+ *
14120
+ * @param omm - A flat OMM JSON object from CelesTrak
14121
+ * @returns Parsed OMM structure with inferred metadata
14122
+ */
14123
+ static parseJson(omm: OmmDataFormat): ParsedOmm;
14124
+ /**
14125
+ * Parse an array of CelesTrak-style flat JSON OMM objects.
14126
+ * @param ommArray - Array of flat OMM JSON objects from CelesTrak
14127
+ * @returns Array of parsed OMM structures
14128
+ */
14129
+ static parseJsonArray(ommArray: OmmDataFormat[]): ParsedOmm[];
14081
14130
  /**
14082
14131
  * Parse all key-value pairs from OMM lines (excluding COMMENT lines).
14083
14132
  */
package/dist/main.js CHANGED
@@ -9855,13 +9855,26 @@ var FormatTle = class _FormatTle {
9855
9855
  const meanaStr = _FormatTle.meanAnomaly(meana);
9856
9856
  const ecenStr = _FormatTle.eccentricity(ecen);
9857
9857
  const intlStr = intl.padEnd(8, " ");
9858
- let TLE1Ending = tleParams.sat ? tleParams.sat.tle1.substring(32, 71) : " +.00000000 +00000+0 +00000-0 0 9990";
9858
+ const classification = tleParams.classification ?? "U";
9859
+ const elementSetNo = (tleParams.elementSetNo ?? 999).toString().padStart(4, " ");
9860
+ const ephemerisType = (tleParams.ephemerisType ?? 0).toString();
9861
+ const revAtEpoch = (tleParams.revAtEpoch ?? 0).toString().padStart(5, " ");
9862
+ let TLE1Ending;
9863
+ if (tleParams.sat) {
9864
+ TLE1Ending = tleParams.sat.tle1.substring(32, 71);
9865
+ } else {
9866
+ const mmDot = _FormatTle.formatMeanMotionDot(tleParams.meanMotionDot ?? 0);
9867
+ const mmDdot = _FormatTle.formatTleExponential(tleParams.meanMotionDdot ?? 0);
9868
+ const bstarStr = _FormatTle.formatTleExponential(tleParams.bstar ?? 0);
9869
+ TLE1Ending = ` ${mmDot} ${mmDdot} ${bstarStr} ${ephemerisType} ${elementSetNo}0`;
9870
+ }
9859
9871
  TLE1Ending = TLE1Ending[1] === " " ? _FormatTle.setCharAt(TLE1Ending, 1, "+") : TLE1Ending;
9860
9872
  TLE1Ending = TLE1Ending[12] === " " ? _FormatTle.setCharAt(TLE1Ending, 12, "+") : TLE1Ending;
9861
9873
  TLE1Ending = TLE1Ending[21] === " " ? _FormatTle.setCharAt(TLE1Ending, 21, "+") : TLE1Ending;
9862
- TLE1Ending = TLE1Ending[32] === " " ? _FormatTle.setCharAt(TLE1Ending, 32, "0") : TLE1Ending;
9863
- const tle1 = `1 ${scc}U ${intlStr} ${epochYrStr}${epochdayStr}${TLE1Ending}`;
9864
- const tle2 = `2 ${scc} ${incStr} ${rascStr} ${ecenStr} ${argPeStr} ${meanaStr} ${meanmoStr} 00010`;
9874
+ const tle1Pre = `1 ${scc}${classification} ${intlStr} ${epochYrStr}${epochdayStr}${TLE1Ending}`;
9875
+ const tle1 = _FormatTle.setCharAt(tle1Pre, 68, _FormatTle.tleChecksum(tle1Pre).toString());
9876
+ const tle2Pre = `2 ${scc} ${incStr} ${rascStr} ${ecenStr} ${argPeStr} ${meanaStr} ${meanmoStr}${revAtEpoch}0`;
9877
+ const tle2 = _FormatTle.setCharAt(tle2Pre, 68, _FormatTle.tleChecksum(tle2Pre).toString());
9865
9878
  return { tle1, tle2 };
9866
9879
  }
9867
9880
  /**
@@ -9990,6 +10003,61 @@ var FormatTle = class _FormatTle {
9990
10003
  }
9991
10004
  return `${str.substring(0, index)}${chr}${str.substring(index + 1)}`;
9992
10005
  }
10006
+ /**
10007
+ * Format mean motion dot (first derivative / 2) for TLE line 1.
10008
+ * Format: sign + ".NNNNNNNN" = 10 chars total.
10009
+ * @param value - Mean motion dot value (rev/day^2)
10010
+ * @returns Formatted 10-character string
10011
+ */
10012
+ static formatMeanMotionDot(value) {
10013
+ const sign2 = value >= 0 ? " " : "-";
10014
+ return sign2 + Math.abs(value).toFixed(8).substring(1);
10015
+ }
10016
+ /**
10017
+ * Format a value in TLE exponential notation for BSTAR or mean motion ddot.
10018
+ * Format: "sNNNNN±N" (8 chars) where mantissa has implied leading decimal point.
10019
+ * Example: 0.00017507 → " 17507-3" (i.e., .17507 × 10^-3)
10020
+ * @param value - The value to format
10021
+ * @returns Formatted 8-character string
10022
+ */
10023
+ static formatTleExponential(value) {
10024
+ if (value === 0) {
10025
+ return " 00000-0";
10026
+ }
10027
+ const sign2 = value >= 0 ? " " : "-";
10028
+ const absVal = Math.abs(value);
10029
+ let exponent = Math.floor(Math.log10(absVal)) + 1;
10030
+ let mantissa = absVal / Math.pow(10, exponent);
10031
+ if (mantissa >= 1) {
10032
+ mantissa /= 10;
10033
+ exponent++;
10034
+ }
10035
+ if (mantissa < 0.1 && mantissa > 0) {
10036
+ mantissa *= 10;
10037
+ exponent--;
10038
+ }
10039
+ const mantissaStr = Math.round(mantissa * 1e5).toString().padStart(5, "0");
10040
+ const expSign = exponent >= 0 ? "+" : "-";
10041
+ const expStr = Math.abs(exponent).toString();
10042
+ return sign2 + mantissaStr + expSign + expStr;
10043
+ }
10044
+ /**
10045
+ * Compute TLE line checksum (modulo 10 sum of digits, '-' counts as 1).
10046
+ * @param line - TLE line (first 68 characters are summed)
10047
+ * @returns Checksum digit (0-9)
10048
+ */
10049
+ static tleChecksum(line) {
10050
+ let sum = 0;
10051
+ for (let i = 0; i < 68 && i < line.length; i++) {
10052
+ const c = line[i];
10053
+ if (c >= "0" && c <= "9") {
10054
+ sum += parseInt(c);
10055
+ } else if (c === "-") {
10056
+ sum += 1;
10057
+ }
10058
+ }
10059
+ return sum % 10;
10060
+ }
9993
10061
  };
9994
10062
 
9995
10063
  // src/coordinate/RelativeState.ts
@@ -16623,8 +16691,9 @@ var Satellite = class _Satellite extends SpaceObject {
16623
16691
  this.satrec = Sgp4.createSatrec(tle1, tle2);
16624
16692
  }
16625
16693
  parseOmmAndUpdateOrbit_(omm) {
16626
- this.sccNum = omm.NORAD_CAT_ID.padStart(5, "0");
16627
- this.sccNum5 = Tle.convert6DigitToA5(omm.NORAD_CAT_ID);
16694
+ const noradStr = String(omm.NORAD_CAT_ID);
16695
+ this.sccNum = noradStr.padStart(5, "0");
16696
+ this.sccNum5 = Tle.convert6DigitToA5(noradStr);
16628
16697
  this.sccNum6 = Tle.convertA5to6Digit(this.sccNum5);
16629
16698
  this.intlDes = omm.OBJECT_ID;
16630
16699
  const YYYY = omm.EPOCH.slice(0, 4);
@@ -16637,6 +16706,19 @@ var Satellite = class _Satellite extends SpaceObject {
16637
16706
  const dayOfYear = (epochDateObj - Date.UTC(Number(YYYY), 0, 0)) / 864e5;
16638
16707
  const ommParsed = {
16639
16708
  ...omm,
16709
+ NORAD_CAT_ID: noradStr,
16710
+ MEAN_MOTION: String(omm.MEAN_MOTION),
16711
+ ECCENTRICITY: String(omm.ECCENTRICITY),
16712
+ INCLINATION: String(omm.INCLINATION),
16713
+ RA_OF_ASC_NODE: String(omm.RA_OF_ASC_NODE),
16714
+ ARG_OF_PERICENTER: String(omm.ARG_OF_PERICENTER),
16715
+ MEAN_ANOMALY: String(omm.MEAN_ANOMALY),
16716
+ EPHEMERIS_TYPE: String(omm.EPHEMERIS_TYPE),
16717
+ ELEMENT_SET_NO: String(omm.ELEMENT_SET_NO),
16718
+ REV_AT_EPOCH: String(omm.REV_AT_EPOCH),
16719
+ BSTAR: String(omm.BSTAR),
16720
+ MEAN_MOTION_DOT: String(omm.MEAN_MOTION_DOT),
16721
+ MEAN_MOTION_DDOT: String(omm.MEAN_MOTION_DDOT),
16640
16722
  epoch: {
16641
16723
  year: Number(YYYY),
16642
16724
  month: Number(MM),
@@ -16649,20 +16731,41 @@ var Satellite = class _Satellite extends SpaceObject {
16649
16731
  };
16650
16732
  this.epochYear = parseInt(YYYY.slice(2, 4));
16651
16733
  this.epochDay = dayOfYear;
16652
- this.meanMoDev1 = parseFloat(omm.MEAN_MOTION_DOT);
16653
- this.meanMoDev2 = parseFloat(omm.MEAN_MOTION_DDOT);
16654
- this.bstar = parseFloat(omm.BSTAR);
16655
- this.inclination = parseFloat(omm.INCLINATION);
16656
- this.rightAscension = parseFloat(omm.RA_OF_ASC_NODE);
16657
- this.eccentricity = parseFloat(omm.ECCENTRICITY);
16658
- this.argOfPerigee = parseFloat(omm.ARG_OF_PERICENTER);
16659
- this.meanAnomaly = parseFloat(omm.MEAN_ANOMALY);
16660
- this.meanMotion = parseFloat(omm.MEAN_MOTION);
16734
+ this.meanMoDev1 = Number(omm.MEAN_MOTION_DOT);
16735
+ this.meanMoDev2 = Number(omm.MEAN_MOTION_DDOT);
16736
+ this.bstar = Number(omm.BSTAR);
16737
+ this.inclination = Number(omm.INCLINATION);
16738
+ this.rightAscension = Number(omm.RA_OF_ASC_NODE);
16739
+ this.eccentricity = Number(omm.ECCENTRICITY);
16740
+ this.argOfPerigee = Number(omm.ARG_OF_PERICENTER);
16741
+ this.meanAnomaly = Number(omm.MEAN_ANOMALY);
16742
+ this.meanMotion = Number(omm.MEAN_MOTION);
16661
16743
  this.period = 1440 / this.meanMotion;
16662
16744
  this.semiMajorAxis = (8681663653e-3 / this.meanMotion) ** (2 / 3);
16663
16745
  this.semiMinorAxis = this.semiMajorAxis * Math.sqrt(1 - this.eccentricity ** 2);
16664
16746
  this.apogee = this.semiMajorAxis * (1 + this.eccentricity) - 6371;
16665
16747
  this.perigee = this.semiMajorAxis * (1 - this.eccentricity) - 6371;
16748
+ const { tle1, tle2 } = FormatTle.createTle({
16749
+ inc: this.inclination,
16750
+ meanmo: this.meanMotion,
16751
+ rasc: this.rightAscension,
16752
+ argPe: this.argOfPerigee,
16753
+ meana: this.meanAnomaly,
16754
+ ecen: this.eccentricity,
16755
+ epochyr: this.epochYear,
16756
+ epochday: this.epochDay,
16757
+ intl: omm.OBJECT_ID,
16758
+ scc: this.sccNum,
16759
+ bstar: this.bstar,
16760
+ meanMotionDot: this.meanMoDev1,
16761
+ meanMotionDdot: this.meanMoDev2,
16762
+ classification: String(omm.CLASSIFICATION_TYPE) || "U",
16763
+ revAtEpoch: Number(omm.REV_AT_EPOCH) || 0,
16764
+ elementSetNo: Number(omm.ELEMENT_SET_NO) || 999,
16765
+ ephemerisType: Number(omm.EPHEMERIS_TYPE) || 0
16766
+ });
16767
+ this.tle1 = tle1;
16768
+ this.tle2 = tle2;
16666
16769
  this.satrec = Sgp4.createSatrecFromOmm(ommParsed);
16667
16770
  }
16668
16771
  // ==================== Type Checking ====================
@@ -25178,6 +25281,61 @@ var OmmParser = class _OmmParser {
25178
25281
  const theory = omm.metadata.MEAN_ELEMENT_THEORY.toUpperCase();
25179
25282
  return theory === "SGP" || theory === "SGP4" || theory === "SGP4-XP";
25180
25283
  }
25284
+ /**
25285
+ * Parse a CelesTrak-style flat JSON OMM object into the structured ParsedOmm format.
25286
+ *
25287
+ * CelesTrak's JSON OMM format is a flat object with all fields at the top level,
25288
+ * omitting metadata fields like CENTER_NAME, REF_FRAME, TIME_SYSTEM, and
25289
+ * MEAN_ELEMENT_THEORY (which are always EARTH/TEME/UTC/SGP4 for GP data).
25290
+ *
25291
+ * @param omm - A flat OMM JSON object from CelesTrak
25292
+ * @returns Parsed OMM structure with inferred metadata
25293
+ */
25294
+ static parseJson(omm) {
25295
+ const result = {
25296
+ header: {
25297
+ CCSDS_OMM_VERS: "3.0",
25298
+ CREATION_DATE: (/* @__PURE__ */ new Date()).toISOString(),
25299
+ ORIGINATOR: "CelesTrak"
25300
+ },
25301
+ metadata: {
25302
+ OBJECT_NAME: omm.OBJECT_NAME,
25303
+ OBJECT_ID: omm.OBJECT_ID,
25304
+ CENTER_NAME: "EARTH",
25305
+ REF_FRAME: "TEME",
25306
+ TIME_SYSTEM: "UTC",
25307
+ MEAN_ELEMENT_THEORY: "SGP4"
25308
+ },
25309
+ meanElements: {
25310
+ EPOCH: omm.EPOCH,
25311
+ MEAN_MOTION: Number(omm.MEAN_MOTION),
25312
+ ECCENTRICITY: Number(omm.ECCENTRICITY),
25313
+ INCLINATION: Number(omm.INCLINATION),
25314
+ RA_OF_ASC_NODE: Number(omm.RA_OF_ASC_NODE),
25315
+ ARG_OF_PERICENTER: Number(omm.ARG_OF_PERICENTER),
25316
+ MEAN_ANOMALY: Number(omm.MEAN_ANOMALY)
25317
+ },
25318
+ tleParameters: {
25319
+ EPHEMERIS_TYPE: Number(omm.EPHEMERIS_TYPE),
25320
+ CLASSIFICATION_TYPE: String(omm.CLASSIFICATION_TYPE),
25321
+ NORAD_CAT_ID: Number(omm.NORAD_CAT_ID),
25322
+ ELEMENT_SET_NO: Number(omm.ELEMENT_SET_NO),
25323
+ REV_AT_EPOCH: Number(omm.REV_AT_EPOCH),
25324
+ BSTAR: Number(omm.BSTAR),
25325
+ MEAN_MOTION_DOT: Number(omm.MEAN_MOTION_DOT),
25326
+ MEAN_MOTION_DDOT: Number(omm.MEAN_MOTION_DDOT)
25327
+ }
25328
+ };
25329
+ return result;
25330
+ }
25331
+ /**
25332
+ * Parse an array of CelesTrak-style flat JSON OMM objects.
25333
+ * @param ommArray - Array of flat OMM JSON objects from CelesTrak
25334
+ * @returns Array of parsed OMM structures
25335
+ */
25336
+ static parseJsonArray(ommArray) {
25337
+ return ommArray.map((omm) => _OmmParser.parseJson(omm));
25338
+ }
25181
25339
  /**
25182
25340
  * Parse all key-value pairs from OMM lines (excluding COMMENT lines).
25183
25341
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ootk",
3
- "version": "6.0.1",
3
+ "version": "6.0.2",
4
4
  "type": "module",
5
5
  "description": "Orbital Object Toolkit including Multiple Propagators, Initial Orbit Determination, and Maneuver Calculations.",
6
6
  "exports": {