ootk 6.0.4 → 6.0.7

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
@@ -79,6 +79,7 @@ var AngularDistanceMethod = /* @__PURE__ */ ((AngularDistanceMethod2) => {
79
79
 
80
80
  // src/enums/CatalogSource.ts
81
81
  var CatalogSource = /* @__PURE__ */ ((CatalogSource2) => {
82
+ CatalogSource2["UNKNOWN"] = "unknown";
82
83
  CatalogSource2["USSF"] = "spacetrack";
83
84
  CatalogSource2["CELESTRAK"] = "celestrak";
84
85
  CatalogSource2["CELESTRAK_SUP"] = "celestrak-sup";
@@ -300,7 +301,7 @@ var Epoch = class {
300
301
  const currentDateObj = this.toDateTime();
301
302
  const epochYear = currentDateObj.getUTCFullYear().toString().slice(2, 4);
302
303
  const epochDay = this.getDayOfYear_(currentDateObj);
303
- const timeOfDay = (currentDateObj.getUTCHours() * 60 + currentDateObj.getUTCMinutes()) / 1440;
304
+ const timeOfDay = (currentDateObj.getUTCHours() * 3600 + currentDateObj.getUTCMinutes() * 60 + currentDateObj.getUTCSeconds() + currentDateObj.getUTCMilliseconds() / 1e3) / 86400;
304
305
  const epochDayStr = (epochDay + timeOfDay).toFixed(8).padStart(12, "0");
305
306
  return {
306
307
  epochYr: epochYear,
@@ -2245,6 +2246,32 @@ function createSampleCovarianceFromTle(tleLine1, tleLine2, frame = "ric" /* RIC
2245
2246
  const sample = new CovarianceSample(j2000State, covariance2, tle);
2246
2247
  return frame === "ric" /* RIC */ ? sample.desampleRIC() : sample.desampleJ2000();
2247
2248
  }
2249
+ var DEFAULT_SCREENING_SIGMA_CAPS = [1200, 1e3, 5e3];
2250
+ function cappedScreeningCovarianceFromTle(tleLine1, tleLine2, confidenceLevel, caps = DEFAULT_SCREENING_SIGMA_CAPS) {
2251
+ let elements;
2252
+ try {
2253
+ elements = createSampleCovarianceFromTle(tleLine1, tleLine2).matrix.elements;
2254
+ } catch {
2255
+ return buildFallbackScreeningCovariance_(caps);
2256
+ }
2257
+ const radialVar = elements[0][0];
2258
+ const intrackVar = elements[1][1];
2259
+ const crosstrackVar = elements[2][2];
2260
+ elements[0][0] = Math.min(Math.sqrt(radialVar) * confidenceLevel, caps[0]);
2261
+ elements[1][1] = Math.min(Math.sqrt(crosstrackVar) * confidenceLevel, caps[1]);
2262
+ elements[2][2] = Math.min(Math.sqrt(intrackVar) * confidenceLevel, caps[2]);
2263
+ if (!elements[0][0] || !elements[1][1] || !elements[2][2]) {
2264
+ return buildFallbackScreeningCovariance_(caps);
2265
+ }
2266
+ return new StateCovariance(new Matrix(elements), "eci" /* ECI */);
2267
+ }
2268
+ function buildFallbackScreeningCovariance_(caps) {
2269
+ const fallback = Array.from({ length: 6 }, () => new Array(6).fill(0));
2270
+ fallback[0][0] = caps[0];
2271
+ fallback[1][1] = caps[1];
2272
+ fallback[2][2] = caps[2];
2273
+ return new StateCovariance(new Matrix(fallback), "eci" /* ECI */);
2274
+ }
2248
2275
 
2249
2276
  // src/utils/jacobian.ts
2250
2277
  var jacobian = (f, m, x0, step = 1e-5) => {
@@ -2271,6 +2298,17 @@ function linearDistance(pos1, pos2) {
2271
2298
  return Math.sqrt((pos1.x - pos2.x) ** 2 + (pos1.y - pos2.y) ** 2 + (pos1.z - pos2.z) ** 2);
2272
2299
  }
2273
2300
 
2301
+ // src/utils/photometry.ts
2302
+ var RCS_VMAG_ESTIMATE_MIN = -5;
2303
+ var RCS_VMAG_ESTIMATE_MAX = 15;
2304
+ function estimateVmagFromRcs(rcs) {
2305
+ if (typeof rcs !== "number" || !Number.isFinite(rcs) || rcs <= 0) {
2306
+ return null;
2307
+ }
2308
+ const vmag = -1.3 - 2.5 * Math.log10(rcs);
2309
+ return Math.min(Math.max(vmag, RCS_VMAG_ESTIMATE_MIN), RCS_VMAG_ESTIMATE_MAX);
2310
+ }
2311
+
2274
2312
  // src/operations/Vector3D.ts
2275
2313
  var Vector3D = class _Vector3D {
2276
2314
  constructor(x, y, z) {
@@ -3255,7 +3293,7 @@ var Random = class {
3255
3293
  }
3256
3294
  };
3257
3295
 
3258
- // ../../../node_modules/astronomy-engine/esm/astronomy.js
3296
+ // node_modules/astronomy-engine/esm/astronomy.js
3259
3297
  var C_AUDAY = 173.1446326846693;
3260
3298
  var KM_PER_AU2 = 14959787069098932e-8;
3261
3299
  var DEG2RAD2 = 0.017453292519943295;
@@ -9028,6 +9066,7 @@ var OemParser = class _OemParser {
9028
9066
  let currentBlock = null;
9029
9067
  let currentMetadata = {};
9030
9068
  let metadataComments = [];
9069
+ let userDefined = {};
9031
9070
  let inMeta = false;
9032
9071
  let inData = false;
9033
9072
  let inCovariance = false;
@@ -9036,6 +9075,7 @@ var OemParser = class _OemParser {
9036
9075
  if (line === "META_START") {
9037
9076
  currentMetadata = {};
9038
9077
  metadataComments = [];
9078
+ userDefined = {};
9039
9079
  inMeta = true;
9040
9080
  continue;
9041
9081
  }
@@ -9043,6 +9083,9 @@ var OemParser = class _OemParser {
9043
9083
  if (metadataComments.length > 0) {
9044
9084
  currentMetadata.COMMENT = metadataComments;
9045
9085
  }
9086
+ if (Object.keys(userDefined).length > 0) {
9087
+ currentMetadata.USER_DEFINED = userDefined;
9088
+ }
9046
9089
  currentBlock = {
9047
9090
  metadata: currentMetadata,
9048
9091
  ephemeris: []
@@ -9081,7 +9124,9 @@ var OemParser = class _OemParser {
9081
9124
  const eqIndex = line.indexOf("=");
9082
9125
  const key = line.substring(0, eqIndex).trim();
9083
9126
  const value = line.substring(eqIndex + 1).trim();
9084
- if (key === "INTERPOLATION_DEGREE") {
9127
+ if (key.startsWith("USER_DEFINED_")) {
9128
+ userDefined[key.substring(13)] = value;
9129
+ } else if (key === "INTERPOLATION_DEGREE") {
9085
9130
  currentMetadata[key] = parseInt(value, 10);
9086
9131
  } else {
9087
9132
  currentMetadata[key] = value;
@@ -9849,7 +9894,10 @@ var FormatTle = class _FormatTle {
9849
9894
  */
9850
9895
  static createTle(tleParams) {
9851
9896
  const { inc, meanmo, rasc, argPe, meana, ecen, epochyr, epochday, intl } = tleParams;
9852
- const scc = Tle.convert6DigitToA5(tleParams.scc);
9897
+ let scc = Tle.convert6DigitToA5(tleParams.scc);
9898
+ if (/^\d{1,4}$/u.test(scc)) {
9899
+ scc = scc.padStart(5, "0");
9900
+ }
9853
9901
  const epochYrStr = String(epochyr).padStart(2, "0");
9854
9902
  const epochdayStr = Number(epochday).toFixed(8).padStart(12, "0");
9855
9903
  const incStr = _FormatTle.inclination(inc);
@@ -10362,7 +10410,7 @@ var Sgp4 = class _Sgp4 {
10362
10410
  error: 0 /* NO_ERROR */
10363
10411
  };
10364
10412
  const xpdotp = 1440 / (2 * PI);
10365
- satrec.satnum = tleLine1.substring(2, 7);
10413
+ satrec.satnum = tleLine1.charAt(7) === "V" ? "0" : tleLine1.substring(2, 7);
10366
10414
  satrec.epochyr = parseInt(tleLine1.substring(18, 20));
10367
10415
  satrec.epochdays = parseFloat(tleLine1.substring(20, 32));
10368
10416
  satrec.ndot = parseFloat(tleLine1.substring(33, 43));
@@ -13880,7 +13928,7 @@ var Tle = class _Tle {
13880
13928
  this.line1 = line1;
13881
13929
  this.line2 = line2;
13882
13930
  this.epoch = _Tle.parseEpoch_(line1.substring(18, 32));
13883
- this.satnum = parseInt(_Tle.convertA5to6Digit(line1.substring(2, 7)));
13931
+ this.satnum = _Tle.satNum(this.line1);
13884
13932
  this.satrec_ = Sgp4.createSatrec(line1, line2, gravConst, opsMode);
13885
13933
  }
13886
13934
  toString() {
@@ -13969,7 +14017,7 @@ ${this.line2}`;
13969
14017
  epochYearFull = 1900 + epochYearShort;
13970
14018
  }
13971
14019
  const epochJday = epochDayOfYear + epochYearFull * 365;
13972
- const currentJday = getDayOfYear() + currentYearFull * 365;
14020
+ const currentJday = getDayOfYear(nowInput) + currentYearFull * 365;
13973
14021
  const currentTime = (nowInput.getUTCHours() * 3600 + nowInput.getUTCMinutes() * 60 + nowInput.getUTCSeconds()) / 86400;
13974
14022
  const daysOld = currentJday + currentTime - epochJday;
13975
14023
  switch (outputUnits) {
@@ -14117,7 +14165,7 @@ ${this.line2}`;
14117
14165
  const BSTAR_PART_3 = _Tle.bstar_.start + 6;
14118
14166
  const BSTAR_PART_4 = _Tle.bstar_.stop - 1;
14119
14167
  const bstarSymbol = tleLine1.substring(_Tle.bstar_.start, BSTAR_PART_2);
14120
- let bstar1 = parseFloat(`0.${tleLine1.substring(BSTAR_PART_2, BSTAR_PART_3)}`);
14168
+ const mantissaFraction = tleLine1.substring(BSTAR_PART_2, BSTAR_PART_3);
14121
14169
  const exponentSymbol = tleLine1.substring(BSTAR_PART_3, BSTAR_PART_4);
14122
14170
  let exponent = parseInt(tleLine1.substring(BSTAR_PART_4, _Tle.bstar_.stop));
14123
14171
  if (exponentSymbol === "-") {
@@ -14125,12 +14173,16 @@ ${this.line2}`;
14125
14173
  } else if (exponentSymbol !== "+" && exponentSymbol !== " " && exponentSymbol !== "0") {
14126
14174
  throw new ParseError(`Invalid BSTAR exponent symbol: ${exponentSymbol}`, "TLE");
14127
14175
  }
14128
- bstar1 *= 10 ** exponent;
14176
+ let sign2 = 1;
14177
+ let integerPart = "0";
14129
14178
  if (bstarSymbol === "-") {
14130
- bstar1 *= -1;
14131
- } else if (bstarSymbol === "+" || bstarSymbol === " " || bstarSymbol === "0") ; else {
14179
+ sign2 = -1;
14180
+ } else if (bstarSymbol === "+" || bstarSymbol === " " || bstarSymbol === "0") ; else if (/^\d$/u.test(bstarSymbol)) {
14181
+ integerPart = bstarSymbol;
14182
+ } else {
14132
14183
  throw new ParseError(`Invalid BSTAR symbol: ${bstarSymbol}`, "TLE");
14133
14184
  }
14185
+ const bstar1 = sign2 * parseFloat(`${integerPart}.${mantissaFraction}`) * 10 ** exponent;
14134
14186
  return toPrecision(bstar1, 14);
14135
14187
  }
14136
14188
  /**
@@ -14185,22 +14237,25 @@ ${this.line2}`;
14185
14237
  }
14186
14238
  /**
14187
14239
  * Private value - used by United States Space Force to reference the orbit model used to generate the Tle. Will
14188
- * always be seen as zero externally (e.g. by "us", unless you are "them" - in which case, hello!).
14240
+ * almost always be seen as zero externally (e.g. by "us", unless you are "them" - in which case, hello!).
14189
14241
  *
14190
- * Starting in 2024, this may contain a 4 if the Tle was generated using the new SGP4-XP model. Until the source code
14191
- * is released, there is no way to support that format in JavaScript or TypeScript.
14242
+ * A value of 1 is tolerated in addition to 0: the field is informational and does not change how SGP4/SDP4
14243
+ * propagate the element set, and a handful of archival TLEs carry a 1 (originally an SGP marker).
14244
+ *
14245
+ * A value of 4 indicates the SGP4-XP model. Until that source code is released there is no way to support that
14246
+ * format in JavaScript or TypeScript, so it is rejected explicitly. Any other value is treated as malformed.
14192
14247
  * @example 0
14193
14248
  * @param tleLine1 The first line of the Tle to parse.
14194
- * @returns The ephemeris type.
14249
+ * @returns The ephemeris type (0 or 1).
14195
14250
  */
14196
14251
  static ephemerisType(tleLine1) {
14197
14252
  const ephemerisType = parseInt(tleLine1.substring(_Tle.ephemerisType_.start, _Tle.ephemerisType_.stop));
14198
- if (ephemerisType !== 0 && ephemerisType !== 4) {
14199
- throw new ParseError(`Invalid ephemeris type: ${ephemerisType}`, "TLE");
14200
- }
14201
14253
  if (ephemerisType === 4) {
14202
14254
  throw new ParseError("SGP4-XP ephemeris type is not supported", "TLE");
14203
14255
  }
14256
+ if (ephemerisType !== 0 && ephemerisType !== 1) {
14257
+ throw new ParseError(`Invalid ephemeris type: ${ephemerisType}`, "TLE");
14258
+ }
14204
14259
  return ephemerisType;
14205
14260
  }
14206
14261
  /**
@@ -14431,6 +14486,9 @@ ${this.line2}`;
14431
14486
  */
14432
14487
  static satNum(tleLine) {
14433
14488
  const satNumStr = tleLine.substring(_Tle.satNum_.start, _Tle.satNum_.stop);
14489
+ if (satNumStr.trim().length === 0) {
14490
+ return NaN;
14491
+ }
14434
14492
  const sixDigitSatNum = _Tle.convertA5to6Digit(satNumStr);
14435
14493
  return parseInt(sixDigitSatNum);
14436
14494
  }
@@ -14521,16 +14579,23 @@ ${this.line2}`;
14521
14579
  static parse(tleLine1, tleLine2) {
14522
14580
  const line1 = _Tle.parseLine1(tleLine1);
14523
14581
  const line2 = _Tle.parseLine2(tleLine2);
14524
- if (line1.satNum !== line2.satNum) {
14582
+ const isVimpel = line1.classification === "V";
14583
+ if (!isVimpel && line1.satNum !== line2.satNum) {
14584
+ console.info("Line 1 satNum:", line1.satNum);
14585
+ console.info("Line 2 satNum:", line2.satNum);
14525
14586
  throw new ParseError("Satellite numbers do not match between TLE lines", "TLE");
14526
14587
  }
14527
- if (line1.satNumRaw !== line2.satNumRaw) {
14588
+ if (!isVimpel && line1.satNumRaw !== line2.satNumRaw) {
14589
+ console.info("Line 1 satNumRaw:", line1.satNumRaw);
14590
+ console.info("Line 2 satNumRaw:", line2.satNumRaw);
14528
14591
  throw new ParseError("Raw satellite numbers do not match between TLE lines", "TLE");
14529
14592
  }
14530
14593
  if (line1.lineNumber1 !== 1) {
14594
+ console.info("Line 1 line number:", line1.lineNumber1);
14531
14595
  throw new ParseError("First TLE line number must be 1", "TLE");
14532
14596
  }
14533
14597
  if (line2.lineNumber2 !== 2) {
14598
+ console.info("Line 2 line number:", line2.lineNumber2);
14534
14599
  throw new ParseError("Second TLE line number must be 2", "TLE");
14535
14600
  }
14536
14601
  return {
@@ -14561,10 +14626,11 @@ ${this.line2}`;
14561
14626
  static parseAll(tleLine1, tleLine2) {
14562
14627
  const line1 = _Tle.parseLine1(tleLine1);
14563
14628
  const line2 = _Tle.parseLine2(tleLine2);
14564
- if (line1.satNum !== line2.satNum) {
14629
+ const isVimpel = line1.classification === "V";
14630
+ if (!isVimpel && line1.satNum !== line2.satNum) {
14565
14631
  throw new ParseError("Satellite numbers do not match between TLE lines", "TLE");
14566
14632
  }
14567
- if (line1.satNumRaw !== line2.satNumRaw) {
14633
+ if (!isVimpel && line1.satNumRaw !== line2.satNumRaw) {
14568
14634
  throw new ParseError("Raw satellite numbers do not match between TLE lines", "TLE");
14569
14635
  }
14570
14636
  if (line1.lineNumber1 !== 1) {
@@ -14576,9 +14642,44 @@ ${this.line2}`;
14576
14642
  return { ...line1, ...line2 };
14577
14643
  }
14578
14644
  /**
14579
- * Converts a 6 digit SCC number to a 5 digit SCC alpha 5 number
14580
- * @param sccNum The 6 digit SCC number
14581
- * @returns The 5 digit SCC alpha 5 number
14645
+ * Classifies a satellite catalog number by representation. See {@link SatNumKind}.
14646
+ * Pure function; no side effects.
14647
+ * @param sccNum The catalog number string.
14648
+ * @returns The {@link SatNumKind} describing the input.
14649
+ */
14650
+ static classifySatNum(sccNum) {
14651
+ if (typeof sccNum !== "string") {
14652
+ return "invalid";
14653
+ }
14654
+ const trimmed = sccNum.trim();
14655
+ if (trimmed.length === 0) {
14656
+ return "invalid";
14657
+ }
14658
+ const first = trimmed[0];
14659
+ if (trimmed.length === 5 && first in _Tle.alpha5_) {
14660
+ return /^\d{4}$/u.test(trimmed.slice(1)) ? "alpha5" : "invalid";
14661
+ }
14662
+ if (!/^\d+$/u.test(trimmed)) {
14663
+ return "invalid";
14664
+ }
14665
+ if (trimmed.length <= 5) {
14666
+ return "numeric5";
14667
+ }
14668
+ if (trimmed.length === 6) {
14669
+ return parseInt(trimmed, 10) <= 339999 ? "numeric6" : "extended";
14670
+ }
14671
+ return "extended";
14672
+ }
14673
+ /**
14674
+ * Converts a 6-digit numeric SCC number to its 5-character alpha-5 form.
14675
+ *
14676
+ * Inputs shorter than 6 chars or already in alpha-5 form pass through unchanged.
14677
+ *
14678
+ * @param sccNum The SCC number to convert.
14679
+ * @returns The 5-character alpha-5 representation.
14680
+ * @throws {ValidationError} If `sccNum` exceeds the alpha-5 range (numeric value > 339 999,
14681
+ * or length > 6). For such IDs the canonical value should be kept on
14682
+ * `Satellite.sccNum` and the TLE column populated with the last 5 digits.
14582
14683
  */
14583
14684
  static convert6DigitToA5(sccNum) {
14584
14685
  if (sccNum.length < 6) {
@@ -14587,9 +14688,27 @@ ${this.line2}`;
14587
14688
  if (typeof sccNum[0] !== "string") {
14588
14689
  throw new ParseError("Invalid SCC number format", "TLE");
14589
14690
  }
14691
+ if (sccNum.length > 6) {
14692
+ throw new ValidationError(
14693
+ "SCC number exceeds TLE alpha-5 capacity (max 339999); use Satellite.sccNum for the canonical ID",
14694
+ "sccNum",
14695
+ sccNum
14696
+ );
14697
+ }
14590
14698
  if (RegExp(/[A-Z]/iu, "u").test(sccNum[0])) {
14591
14699
  return sccNum;
14592
14700
  }
14701
+ const numericValue = parseInt(sccNum, 10);
14702
+ if (isNaN(numericValue)) {
14703
+ throw new ValidationError("SCC number must be numeric", "sccNum", sccNum);
14704
+ }
14705
+ if (numericValue > 339999) {
14706
+ throw new ValidationError(
14707
+ "SCC number exceeds TLE alpha-5 capacity (max 339999); use Satellite.sccNum for the canonical ID",
14708
+ "sccNum",
14709
+ sccNum
14710
+ );
14711
+ }
14593
14712
  const rest = sccNum.slice(2, 6);
14594
14713
  let first = parseInt(`${sccNum[0]}${sccNum[1]}`);
14595
14714
  const iPlus = first >= 18 ? 1 : 0;
@@ -14598,9 +14717,17 @@ ${this.line2}`;
14598
14717
  return `${String.fromCharCode(first + 55)}${rest}`;
14599
14718
  }
14600
14719
  /**
14601
- * Converts a 5-digit SCC number to a 6-digit SCC number.
14602
- * @param sccNum - The 5-digit SCC number to convert.
14603
- * @returns The converted 6-digit SCC number.
14720
+ * Converts a 5-character alpha-5 SCC number to its 6-digit numeric form.
14721
+ *
14722
+ * Inputs shorter than 5 chars pass through unchanged. Numeric inputs without
14723
+ * an alpha-5 leading letter pass through unchanged (5-digit numeric, in-range
14724
+ * 6-digit numeric, and extended 7+ digit numeric IDs are all identity).
14725
+ *
14726
+ * @param sccNum The SCC number to convert.
14727
+ * @returns The 6-digit numeric representation, or the input itself if it
14728
+ * is already a numeric form.
14729
+ * @throws {ValidationError} If `sccNum` is malformed: 6-digit numeric whose
14730
+ * value exceeds 339 999, or contains stray letters in a non-leading position.
14604
14731
  */
14605
14732
  static convertA5to6Digit(sccNum) {
14606
14733
  if (sccNum.length < 5) {
@@ -14611,10 +14738,33 @@ ${this.line2}`;
14611
14738
  throw new ParseError("Invalid SCC number format", "TLE");
14612
14739
  }
14613
14740
  if (values[0] in _Tle.alpha5_) {
14741
+ if (!/^\d+$/u.test(sccNum.slice(1))) {
14742
+ throw new ValidationError(
14743
+ "Alpha-5 SCC number must have 4 trailing digits",
14744
+ "sccNum",
14745
+ sccNum
14746
+ );
14747
+ }
14614
14748
  const firstLetter = values[0];
14615
14749
  values[0] = _Tle.alpha5_[firstLetter];
14750
+ return values.join("");
14751
+ }
14752
+ if (!/^\s*\d+\s*$/u.test(sccNum)) {
14753
+ throw new ValidationError(
14754
+ "SCC number must be alpha-5 or all-numeric",
14755
+ "sccNum",
14756
+ sccNum
14757
+ );
14758
+ }
14759
+ const trimmed = sccNum.trim();
14760
+ if (trimmed.length === 6 && parseInt(trimmed, 10) > 339999) {
14761
+ throw new ValidationError(
14762
+ "6-digit SCC number exceeds TLE alpha-5 capacity (max 339999)",
14763
+ "sccNum",
14764
+ sccNum
14765
+ );
14616
14766
  }
14617
- return values.join("");
14767
+ return sccNum;
14618
14768
  }
14619
14769
  };
14620
14770
 
@@ -16497,11 +16647,15 @@ var Satellite = class _Satellite extends SpaceObject {
16497
16647
  period;
16498
16648
  rightAscension;
16499
16649
  satrec;
16500
- /** The satellite catalog number as listed in the TLE. */
16650
+ /** The canonical satellite catalog number. May be a 5-digit numeric, alpha-5,
16651
+ * 6-digit numeric, or an extended (7+ digit) ID such as CelesTrak supplemental
16652
+ * 9-digit IDs. */
16501
16653
  sccNum;
16502
- /** The 5 digit alpha-numeric satellite catalog number. */
16654
+ /** The 5-character alpha-5 representation, or `null` when {@link sccNum} is
16655
+ * an extended ID that exceeds the alpha-5 capacity (max numeric value 339 999). */
16503
16656
  sccNum5;
16504
- /** The 6 digit numeric satellite catalog number. */
16657
+ /** The 6-digit numeric representation, or `null` when {@link sccNum} is
16658
+ * an extended ID that exceeds the alpha-5 capacity (max numeric value 339 999). */
16505
16659
  sccNum6;
16506
16660
  tle1;
16507
16661
  tle2;
@@ -16683,13 +16837,57 @@ var Satellite = class _Satellite extends SpaceObject {
16683
16837
  return new _Satellite({ omm, name: name ?? omm.OBJECT_NAME });
16684
16838
  }
16685
16839
  // ==================== TLE/OMM Parsing ====================
16840
+ /**
16841
+ * Converts an OMM international designator (e.g. `"2026-114A"`) to the
16842
+ * TLE intl-des column format (cols 10-17, e.g. `"26114A"`). Inputs that
16843
+ * don't match the OMM `YYYY-NNNL...` pattern pass through unchanged.
16844
+ */
16845
+ static ommObjectIdToTleIntlDes_(objectId) {
16846
+ if (!objectId) {
16847
+ return "";
16848
+ }
16849
+ const match = objectId.match(/^\d{4}-(?<rest>\d{3}[A-Z]{1,3})$/u);
16850
+ if (match?.groups?.rest) {
16851
+ return objectId.slice(2, 4) + match.groups.rest;
16852
+ }
16853
+ return objectId;
16854
+ }
16855
+ /**
16856
+ * Normalizes {@link sccNum} to the display-canonical numeric form and derives
16857
+ * {@link sccNum5} and {@link sccNum6}. The class invariant is that
16858
+ * `Satellite.sccNum` is always numeric — never an alpha-5 string. Alpha-5
16859
+ * inputs ("T0001") are converted to their 6-digit numeric equivalent
16860
+ * ("270001"); the alpha-5 form is preserved on {@link sccNum5}.
16861
+ *
16862
+ * Extended (7+ digit) IDs that exceed the alpha-5 capacity (max 339 999)
16863
+ * leave sccNum5/sccNum6 set to `null`.
16864
+ *
16865
+ * Invalid input (empty string, malformed token) is passed through unchanged
16866
+ * so callers can store placeholder sccNums on notional / debris stubs.
16867
+ */
16868
+ assignAlpha5Forms_() {
16869
+ try {
16870
+ this.sccNum = Tle.convertA5to6Digit(this.sccNum);
16871
+ } catch {
16872
+ }
16873
+ if (/^0+\d/u.test(this.sccNum)) {
16874
+ this.sccNum = this.sccNum.replace(/^0+/u, "");
16875
+ }
16876
+ const kind = Tle.classifySatNum(this.sccNum);
16877
+ if (kind === "numeric5" || kind === "numeric6") {
16878
+ this.sccNum5 = Tle.convert6DigitToA5(this.sccNum);
16879
+ this.sccNum6 = this.sccNum;
16880
+ } else {
16881
+ this.sccNum5 = null;
16882
+ this.sccNum6 = null;
16883
+ }
16884
+ }
16686
16885
  parseTleAndUpdateOrbit_(tle1, tle2, sccNum) {
16687
16886
  const tleData = Tle.parse(tle1, tle2);
16688
16887
  this.tle1 = tle1;
16689
16888
  this.tle2 = tle2;
16690
16889
  this.sccNum = sccNum ?? tleData.satNum.toString();
16691
- this.sccNum5 = Tle.convert6DigitToA5(this.sccNum);
16692
- this.sccNum6 = Tle.convertA5to6Digit(this.sccNum5);
16890
+ this.assignAlpha5Forms_();
16693
16891
  this.intlDes = tleData.intlDes;
16694
16892
  this.epochYear = tleData.epochYear;
16695
16893
  this.epochDay = tleData.epochDay;
@@ -16712,8 +16910,7 @@ var Satellite = class _Satellite extends SpaceObject {
16712
16910
  parseOmmAndUpdateOrbit_(omm) {
16713
16911
  const noradStr = String(omm.NORAD_CAT_ID);
16714
16912
  this.sccNum = noradStr.padStart(5, "0");
16715
- this.sccNum5 = Tle.convert6DigitToA5(noradStr);
16716
- this.sccNum6 = Tle.convertA5to6Digit(this.sccNum5);
16913
+ this.assignAlpha5Forms_();
16717
16914
  this.intlDes = omm.OBJECT_ID;
16718
16915
  const YYYY = omm.EPOCH.slice(0, 4);
16719
16916
  const MM = omm.EPOCH.slice(5, 7);
@@ -16773,8 +16970,10 @@ var Satellite = class _Satellite extends SpaceObject {
16773
16970
  ecen: this.eccentricity,
16774
16971
  epochyr: this.epochYear,
16775
16972
  epochday: this.epochDay,
16776
- intl: omm.OBJECT_ID,
16777
- scc: this.sccNum,
16973
+ intl: _Satellite.ommObjectIdToTleIntlDes_(omm.OBJECT_ID),
16974
+ // Extended (7+ digit) IDs don't fit TLE cols 3-7. Truncate to the last 5
16975
+ // digits for the TLE string; the canonical ID stays on this.sccNum.
16976
+ scc: Tle.classifySatNum(this.sccNum) === "extended" ? this.sccNum.slice(-5) : this.sccNum,
16778
16977
  bstar: this.bstar,
16779
16978
  meanMotionDot: this.meanMoDev1,
16780
16979
  meanMotionDdot: this.meanMoDev2,
@@ -21566,6 +21765,82 @@ var ModifiedGoodingIOD = class {
21566
21765
  }
21567
21766
  };
21568
21767
 
21768
+ // src/orbit-determination/Rv2Tle.ts
21769
+ var angleDiff_ = (a, b) => {
21770
+ let diff = (a - b) % TAU;
21771
+ if (diff > Math.PI) {
21772
+ diff -= TAU;
21773
+ } else if (diff < -Math.PI) {
21774
+ diff += TAU;
21775
+ }
21776
+ return diff;
21777
+ };
21778
+ var wrapTau_ = (angle) => {
21779
+ let wrapped = angle % TAU;
21780
+ if (wrapped < 0) {
21781
+ wrapped += TAU;
21782
+ }
21783
+ return wrapped;
21784
+ };
21785
+ var toElements_ = (epoch, position, velocity) => new J20002(
21786
+ epoch,
21787
+ new Vector3D(position.x, position.y, position.z),
21788
+ new Vector3D(velocity.x, velocity.y, velocity.z)
21789
+ ).toClassicalElements();
21790
+ var rv2tle = (epoch, position, velocity, options = {}) => {
21791
+ const maxIterations = options.maxIterations ?? 15;
21792
+ const toleranceKm = options.toleranceKm ?? 1e-4;
21793
+ const epochUtc = EpochUTC.fromDateTime(epoch);
21794
+ const target = toElements_(epochUtc, position, velocity);
21795
+ let mean2 = new ClassicalElements({
21796
+ epoch: epochUtc,
21797
+ semimajorAxis: target.semimajorAxis,
21798
+ eccentricity: target.eccentricity,
21799
+ inclination: target.inclination,
21800
+ rightAscension: target.rightAscension,
21801
+ argPerigee: target.argPerigee,
21802
+ trueAnomaly: target.trueAnomaly
21803
+ });
21804
+ let best = null;
21805
+ for (let iteration = 1; iteration <= maxIterations; iteration++) {
21806
+ let tle;
21807
+ let sv;
21808
+ try {
21809
+ tle = Tle.fromClassicalElements(mean2);
21810
+ const tsinceMin = (epoch.getTime() - tle.epoch.toDateTime().getTime()) / 6e4;
21811
+ sv = Sgp4.propagate(Sgp4.createSatrec(tle.line1, tle.line2), tsinceMin);
21812
+ } catch {
21813
+ return best;
21814
+ }
21815
+ if (!sv.position || typeof sv.position === "boolean" || !sv.velocity || typeof sv.velocity === "boolean") {
21816
+ return best;
21817
+ }
21818
+ const achievedPos = sv.position;
21819
+ const achievedVel = sv.velocity;
21820
+ const dx = achievedPos.x - position.x;
21821
+ const dy = achievedPos.y - position.y;
21822
+ const dz = achievedPos.z - position.z;
21823
+ const positionErrorKm = Math.sqrt(dx * dx + dy * dy + dz * dz);
21824
+ if (!best || positionErrorKm < best.positionErrorKm) {
21825
+ best = { tle1: tle.line1, tle2: tle.line2, positionErrorKm, iterations: iteration };
21826
+ }
21827
+ if (positionErrorKm < toleranceKm) {
21828
+ break;
21829
+ }
21830
+ const achieved = toElements_(epochUtc, achievedPos, achievedVel);
21831
+ mean2 = new ClassicalElements({
21832
+ epoch: epochUtc,
21833
+ semimajorAxis: mean2.semimajorAxis + (target.semimajorAxis - achieved.semimajorAxis),
21834
+ eccentricity: Math.min(Math.max(mean2.eccentricity + (target.eccentricity - achieved.eccentricity), 0), 0.999),
21835
+ inclination: Math.min(Math.max(mean2.inclination + angleDiff_(target.inclination, achieved.inclination), 0), Math.PI),
21836
+ rightAscension: wrapTau_(mean2.rightAscension + angleDiff_(target.rightAscension, achieved.rightAscension)),
21837
+ argPerigee: wrapTau_(mean2.argPerigee + angleDiff_(target.argPerigee, achieved.argPerigee)),
21838
+ trueAnomaly: wrapTau_(mean2.trueAnomaly + angleDiff_(target.trueAnomaly, achieved.trueAnomaly))
21839
+ });
21840
+ }
21841
+ return best;
21842
+ };
21843
+
21569
21844
  // src/covariance/CovarianceSample.ts
21570
21845
  var CovarianceSample = class {
21571
21846
  origin_;
@@ -21758,6 +22033,19 @@ var CovarianceSample = class {
21758
22033
  }
21759
22034
  };
21760
22035
 
22036
+ // src/covariance/displayRadii.ts
22037
+ function scaleAndClampRicSigmas(sigmas, confidence, caps) {
22038
+ const { radial, inTrack, crossTrack } = sigmas;
22039
+ if (![radial, inTrack, crossTrack].every((v) => Number.isFinite(v) && v >= 0)) {
22040
+ return null;
22041
+ }
22042
+ return {
22043
+ radial: Math.min(radial * confidence, caps.radial),
22044
+ inTrack: Math.min(inTrack * confidence, caps.inTrack),
22045
+ crossTrack: Math.min(crossTrack * confidence, caps.crossTrack)
22046
+ };
22047
+ }
22048
+
21761
22049
  // src/conjunction/ConjunctionAssessment.ts
21762
22050
  var ConjunctionAssessment = class {
21763
22051
  constructor(primary, secondary) {
@@ -24182,12 +24470,12 @@ var HorizonsParser = class {
24182
24470
  for (let i = 0; i < lines.length; i++) {
24183
24471
  const line = lines[i].trim();
24184
24472
  if (line.startsWith("Target body name:")) {
24185
- targetName = this.extractValue_(line, "Target body name:");
24473
+ targetName = this.extractTargetName_(line, "Target body name:");
24186
24474
  metadata.targetName = targetName;
24187
24475
  } else if (line.startsWith("Center body name:")) {
24188
24476
  centerBody = this.extractValue_(line, "Center body name:");
24189
24477
  metadata.centerBody = centerBody;
24190
- } else if (line.startsWith("Center-site name:")) {
24478
+ } else if (line.startsWith("Center-site name:") && !centerBody) {
24191
24479
  centerBody = this.extractValue_(line, "Center-site name:");
24192
24480
  metadata.centerBody = centerBody;
24193
24481
  } else if (line.startsWith("Output type:")) {
@@ -24242,7 +24530,7 @@ var HorizonsParser = class {
24242
24530
  for (let i = 0; i < lines.length; i++) {
24243
24531
  const line = lines[i].trim();
24244
24532
  if (line.startsWith("Target body name:")) {
24245
- targetName = this.extractValue_(line, "Target body name:");
24533
+ targetName = this.extractTargetName_(line, "Target body name:");
24246
24534
  } else if (line.startsWith("Center-site name:")) {
24247
24535
  observerLocation = this.extractValue_(line, "Center-site name:");
24248
24536
  }
@@ -24273,7 +24561,23 @@ var HorizonsParser = class {
24273
24561
  */
24274
24562
  static extractValue_(line, key) {
24275
24563
  const value = line.substring(key.length).trim();
24276
- return value.split(/\s{2,}/)[0].trim();
24564
+ return value.split(/\s{2,}/u)[0].trim();
24565
+ }
24566
+ /**
24567
+ * Extracts the target body name, stripping parenthetical descriptors and IDs.
24568
+ *
24569
+ * Horizons format examples:
24570
+ * - "1 Ceres {source: astDys}" → "1 Ceres"
24571
+ * - "Artemis II (spacecraft) (-1024) {source: ...}" → "Artemis II"
24572
+ * - "Mars (499)" → "Mars"
24573
+ */
24574
+ static extractTargetName_(line, key) {
24575
+ const raw = this.extractValue_(line, key);
24576
+ const parenIdx = raw.search(/\s\(/u);
24577
+ if (parenIdx > 0) {
24578
+ return raw.substring(0, parenIdx).trim();
24579
+ }
24580
+ return raw;
24277
24581
  }
24278
24582
  /**
24279
24583
  * Parses a vector data line from Horizons output.
@@ -24343,7 +24647,9 @@ var HorizonsParser = class {
24343
24647
  return null;
24344
24648
  }
24345
24649
  const posLine = allLines[nextIndex].trim();
24346
- const posMatch = posLine.match(/X\s*=\s*([-\d.E+]+)\s+Y\s*=\s*([-\d.E+]+)\s+Z\s*=\s*([-\d.E+]+)/i);
24650
+ const posMatchLabeled = posLine.match(/X\s*=\s*([-\d.E+]+)\s+Y\s*=\s*([-\d.E+]+)\s+Z\s*=\s*([-\d.E+]+)/iu);
24651
+ const posMatchBare = !posMatchLabeled ? posLine.match(/^\s*([-\d.E+]+)\s+([-\d.E+]+)\s+([-\d.E+]+)\s*$/iu) : null;
24652
+ const posMatch = posMatchLabeled ?? posMatchBare;
24347
24653
  if (!posMatch) {
24348
24654
  return null;
24349
24655
  }
@@ -24355,7 +24661,9 @@ var HorizonsParser = class {
24355
24661
  let velocity;
24356
24662
  if (nextIndex < allLines.length) {
24357
24663
  const velLine = allLines[nextIndex].trim();
24358
- const velMatch = velLine.match(/VX\s*=\s*([-\d.E+]+)\s+VY\s*=\s*([-\d.E+]+)\s+VZ\s*=\s*([-\d.E+]+)/i);
24664
+ const velMatchLabeled = velLine.match(/VX\s*=\s*([-\d.E+]+)\s+VY\s*=\s*([-\d.E+]+)\s+VZ\s*=\s*([-\d.E+]+)/iu);
24665
+ const velMatchBare = !velMatchLabeled ? velLine.match(/^\s*([-\d.E+]+)\s+([-\d.E+]+)\s+([-\d.E+]+)\s*$/iu) : null;
24666
+ const velMatch = velMatchLabeled ?? velMatchBare;
24359
24667
  if (velMatch) {
24360
24668
  velocity = new Vector3D(
24361
24669
  parseFloat(velMatch[1]),
@@ -24365,6 +24673,17 @@ var HorizonsParser = class {
24365
24673
  nextIndex++;
24366
24674
  }
24367
24675
  }
24676
+ while (nextIndex < allLines.length) {
24677
+ const extraLine = allLines[nextIndex].trim();
24678
+ if (extraLine === "$$EOE" || extraLine.length === 0 || /^\d+\.\d+\s*=\s*A\.D\./u.test(extraLine)) {
24679
+ break;
24680
+ }
24681
+ if (/^\s*[-\d.E+]+(\s+[-\d.E+]+)*\s*$/u.test(extraLine)) {
24682
+ nextIndex++;
24683
+ } else {
24684
+ break;
24685
+ }
24686
+ }
24368
24687
  return {
24369
24688
  data: { epoch, position, velocity },
24370
24689
  nextIndex
@@ -25111,6 +25430,58 @@ var OdmExporter = class _OdmExporter {
25111
25430
  return lines.join("\n");
25112
25431
  }
25113
25432
  // ==========================================================================
25433
+ // OEM from State Vectors — direct J2000 array export
25434
+ // ==========================================================================
25435
+ /**
25436
+ * Export an array of J2000 state vectors as OEM KVN.
25437
+ *
25438
+ * Unlike {@link formatOem}, which propagates a TLE-based satellite, this
25439
+ * method serializes pre-computed state vectors directly. Useful for
25440
+ * converting parsed ephemeris data (e.g., NASA Horizons) to CCSDS OEM.
25441
+ *
25442
+ * @param stateVectors - Array of J2000 state vectors to export
25443
+ * @param metadata - Object identification metadata
25444
+ * @param options - Export configuration
25445
+ * @returns OEM KVN format string
25446
+ */
25447
+ static formatOemFromStateVectors(stateVectors, metadata, options = {}) {
25448
+ if (stateVectors.length === 0) {
25449
+ throw new Error("Cannot export OEM with no state vectors");
25450
+ }
25451
+ const refFrame = options.refFrame ?? "EME2000";
25452
+ const centerName = options.centerName ?? "EARTH";
25453
+ const startTime = stateVectors[0].epoch.toDateTime();
25454
+ const stopTime = stateVectors[stateVectors.length - 1].epoch.toDateTime();
25455
+ const lines = [];
25456
+ lines.push("CCSDS_OEM_VERS = 2.0");
25457
+ _OdmExporter.appendComments_(lines, options.comments);
25458
+ lines.push(`CREATION_DATE = ${_OdmExporter.formatDateTime_(/* @__PURE__ */ new Date())}`);
25459
+ lines.push(`ORIGINATOR = ${options.originator ?? "KeepTrack"}`);
25460
+ if (options.messageId) {
25461
+ lines.push(`MESSAGE_ID = ${options.messageId}`);
25462
+ }
25463
+ lines.push("");
25464
+ lines.push("META_START");
25465
+ lines.push(`OBJECT_NAME = ${metadata.objectName}`);
25466
+ lines.push(`OBJECT_ID = ${metadata.objectId}`);
25467
+ lines.push(`CENTER_NAME = ${centerName}`);
25468
+ lines.push(`REF_FRAME = ${refFrame}`);
25469
+ lines.push("TIME_SYSTEM = UTC");
25470
+ lines.push(`START_TIME = ${_OdmExporter.formatDateTime_(startTime)}`);
25471
+ lines.push(`STOP_TIME = ${_OdmExporter.formatDateTime_(stopTime)}`);
25472
+ lines.push(`INTERPOLATION = ${options.interpolation ?? "LAGRANGE"}`);
25473
+ lines.push(`INTERPOLATION_DEGREE = ${options.interpolationDegree ?? 7}`);
25474
+ lines.push("META_STOP");
25475
+ lines.push("");
25476
+ for (const sv of stateVectors) {
25477
+ const epoch = _OdmExporter.formatDateTime_(sv.epoch.toDateTime());
25478
+ lines.push(
25479
+ `${epoch} ${_OdmExporter.formatNumber_(sv.position.x)} ${_OdmExporter.formatNumber_(sv.position.y)} ${_OdmExporter.formatNumber_(sv.position.z)} ${_OdmExporter.formatNumber_(sv.velocity.x)} ${_OdmExporter.formatNumber_(sv.velocity.y)} ${_OdmExporter.formatNumber_(sv.velocity.z)}`
25480
+ );
25481
+ }
25482
+ return lines.join("\n");
25483
+ }
25484
+ // ==========================================================================
25114
25485
  // OMM — Orbit Mean-Elements Message
25115
25486
  // ==========================================================================
25116
25487
  /**
@@ -29477,8 +29848,20 @@ var OrbitFinder = class _OrbitFinder {
29477
29848
  this.debug_(`Found perigee at altitude ${perigeeParams.altitude} km`);
29478
29849
  return perigeeParams;
29479
29850
  }
29851
+ /**
29852
+ * Returns the 5-char satnum to embed in the synthesized TLEs.
29853
+ *
29854
+ * Why not {@link Satellite.sccNum}? For extended (7+ digit) IDs sccNum is
29855
+ * the full 9-digit canonical value, which would push the TLE past 69 chars
29856
+ * and break Sgp4.createSatrec. The input tle1 always has a valid 5-char
29857
+ * satnum at columns 2-6, and SGP4 itself doesn't care what value lives
29858
+ * there as long as line 1 and line 2 agree — so use that.
29859
+ */
29860
+ tleSatNum_() {
29861
+ return this.sat_.tle1.substring(2, 7);
29862
+ }
29480
29863
  generateTle1_() {
29481
- return `1 ${this.sat_.sccNum}U ${this.sat_.tle1.substring(9, 17)} ${this.sat_.tle1.substring(18, 32)}${this.sat_.tle1.substring(32, 71)}`;
29864
+ return `1 ${this.tleSatNum_()}U ${this.sat_.tle1.substring(9, 17)} ${this.sat_.tle1.substring(18, 32)}${this.sat_.tle1.substring(32, 71)}`;
29482
29865
  }
29483
29866
  generateTle2_(newParams) {
29484
29867
  const mergedParams = {
@@ -29493,7 +29876,7 @@ var OrbitFinder = class _OrbitFinder {
29493
29876
  const argPer = mergedParams.argOfPerigee.toFixed(4).padStart(8, "0");
29494
29877
  const meanA = mergedParams.meanAnomaly.toFixed(4).padStart(8, "0");
29495
29878
  const meanMo = this.sat_.tle2.substring(52, 63);
29496
- return `2 ${this.sat_.sccNum} ${inc} ${raan} ${ecc} ${argPer} ${meanA} ${meanMo} 10`;
29879
+ return `2 ${this.tleSatNum_()} ${inc} ${raan} ${ecc} ${argPer} ${meanA} ${meanMo} 10`;
29497
29880
  }
29498
29881
  };
29499
29882
 
@@ -29853,6 +30236,33 @@ var RepeatGroundTrack = class _RepeatGroundTrack {
29853
30236
  * You should have received a copy of the GNU Affero General Public License along with
29854
30237
  * Orbital Object ToolKit. If not, see <http://www.gnu.org/licenses/>.
29855
30238
  */
30239
+ /**
30240
+ * @author Theodore Kruczek.
30241
+ * @description Orbital Object ToolKit (ootk) is a collection of tools for working
30242
+ * with satellites and other orbital objects.
30243
+ *
30244
+ * @license MIT License
30245
+ *
30246
+ * @Copyright (c) 2025 Theodore Kruczek
30247
+ *
30248
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
30249
+ * of this software and associated documentation files (the "Software"), to deal
30250
+ * in the Software without restriction, including without limitation the rights
30251
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30252
+ * copies of the Software, and to permit persons to whom the Software is
30253
+ * furnished to do so, subject to the following conditions:
30254
+ *
30255
+ * The above copyright notice and this permission notice shall be included in all
30256
+ * copies or substantial portions of the Software.
30257
+ *
30258
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30259
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30260
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30261
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30262
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30263
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30264
+ * SOFTWARE.
30265
+ */
29856
30266
  /**
29857
30267
  * @author Theodore Kruczek
29858
30268
  * @description Orbital Object ToolKit (ootk) is a collection of tools for working
@@ -30082,6 +30492,8 @@ exports.Quaternion = Quaternion;
30082
30492
  exports.RAD2DEG = RAD2DEG;
30083
30493
  exports.RADIUS_OF_EARTH = RADIUS_OF_EARTH;
30084
30494
  exports.RAE = RAE;
30495
+ exports.RCS_VMAG_ESTIMATE_MAX = RCS_VMAG_ESTIMATE_MAX;
30496
+ exports.RCS_VMAG_ESTIMATE_MIN = RCS_VMAG_ESTIMATE_MIN;
30085
30497
  exports.RIC = RIC;
30086
30498
  exports.RadarSensor = RadarSensor;
30087
30499
  exports.RadecGeocentric = RadecGeocentric;
@@ -30159,6 +30571,7 @@ exports.calcIncFromAz = calcIncFromAz;
30159
30571
  exports.calcInertAz = calcInertAz;
30160
30572
  exports.calculateFspl = calculateFspl;
30161
30573
  exports.calculatePropagationDelay = calculatePropagationDelay;
30574
+ exports.cappedScreeningCovarianceFromTle = cappedScreeningCovarianceFromTle;
30162
30575
  exports.clamp = clamp;
30163
30576
  exports.concat = concat;
30164
30577
  exports.copySign = copySign;
@@ -30183,6 +30596,7 @@ exports.eci2lla = eci2lla;
30183
30596
  exports.eci2rae = eci2rae;
30184
30597
  exports.enu2rf = enu2rf;
30185
30598
  exports.estimateRcs = estimateRcs;
30599
+ exports.estimateVmagFromRcs = estimateVmagFromRcs;
30186
30600
  exports.evalPoly = evalPoly;
30187
30601
  exports.factorial = factorial;
30188
30602
  exports.gamma = gamma;
@@ -30223,6 +30637,8 @@ exports.rae2raeOffBoresight = rae2raeOffBoresight;
30223
30637
  exports.rae2ruv = rae2ruv;
30224
30638
  exports.rae2sez = rae2sez;
30225
30639
  exports.relativeVelocity = relativeVelocity;
30640
+ exports.rv2tle = rv2tle;
30641
+ exports.scaleAndClampRicSigmas = scaleAndClampRicSigmas;
30226
30642
  exports.sec2day = sec2day;
30227
30643
  exports.sec2deg = sec2deg;
30228
30644
  exports.sec2min = sec2min;