@saber-usa/node-common 1.7.16 → 1.7.17

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/src/astro.js CHANGED
@@ -72,6 +72,7 @@ const checkTle = (line1, line2) => {
72
72
  return satrec;
73
73
  }
74
74
  } catch (e) {
75
+ console.error(e);
75
76
  return false; // TLE invalid
76
77
  }
77
78
  };
@@ -188,6 +189,7 @@ const getRaanPrecession = (line1, line2) => {
188
189
  // result is in degrees per day
189
190
  return satrec.nodedot * 1440 * RAD2DEG;
190
191
  } catch (e) {
192
+ console.error(e);
191
193
  return 0;
192
194
  }
193
195
  };
@@ -244,6 +246,7 @@ const getLonAndDrift = (line1, line2, datetime) => {
244
246
  lonDriftDegreesPerDay: diff,
245
247
  };
246
248
  } catch (e) {
249
+ console.error(e);
247
250
  return {
248
251
  latitude: 0,
249
252
  longitude: 0,
@@ -382,7 +385,7 @@ const angleBetween3DCoords = (coord1, coord2, coord3) => {
382
385
  // angle between them (it's scaled by the product of their magnitudes).
383
386
 
384
387
  // Normalize v1
385
- const v1mag = Math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z);
388
+ const v1mag = Math.hypot(v1.x, v1.y, v1.z);
386
389
  const v1norm = {
387
390
  x: v1.x / v1mag,
388
391
  y: v1.y / v1mag,
@@ -390,7 +393,7 @@ const angleBetween3DCoords = (coord1, coord2, coord3) => {
390
393
  };
391
394
 
392
395
  // Normalize v2
393
- const v2mag = Math.sqrt(v2.x * v2.x + v2.y * v2.y + v2.z * v2.z);
396
+ const v2mag = Math.hypot(v2.x, v2.y, v2.z);
394
397
  const v2norm = {
395
398
  x: v2.x / v2mag,
396
399
  y: v2.y / v2mag,
@@ -402,7 +405,7 @@ const angleBetween3DCoords = (coord1, coord2, coord3) => {
402
405
  = v1norm.x * v2norm.x + v1norm.y * v2norm.y + v1norm.z * v2norm.z;
403
406
 
404
407
  // Extract the angle from the dot products
405
- const angle = (Math.acos(dotProducts) * 180.0) / Math.PI;
408
+ const angle = (Math.acos(dotProducts) * 180) / Math.PI;
406
409
 
407
410
  // Round result to 3 decimal points and return
408
411
  return Math.round(angle * 1000) / 1000;
@@ -463,17 +466,17 @@ const planeChangeDeltaV = (pv1, pv2) => {
463
466
 
464
467
  // 1. Compute the angular momentum of each orbit from the pos vel vectors
465
468
  const r = multiply([pv1.position.x, pv1.position.y, pv1.position.z],
466
- 1000.0);
469
+ 1000);
467
470
  const v = multiply([pv1.velocity.x, pv1.velocity.y, pv1.velocity.z],
468
- 1000.0);
471
+ 1000);
469
472
  const h1 = cross(r, v);
470
473
 
471
474
  const vMag = norm(v);
472
475
 
473
476
  const r2 = multiply([pv2.position.x, pv2.position.y, pv2.position.z],
474
- 1000.0);
477
+ 1000);
475
478
  const v2 = multiply([pv2.velocity.x, pv2.velocity.y, pv2.velocity.z],
476
- 1000.0);
479
+ 1000);
477
480
  const h2 = cross(r2, v2);
478
481
 
479
482
  // 2. Compute the mutual line of nodes vector
@@ -543,7 +546,7 @@ const planeChangeDeltaV = (pv1, pv2) => {
543
546
  r: 0,
544
547
  i: dvI,
545
548
  c: dvC,
546
- mag: (dvAsc <= dvDesc) ? dvAsc: dvDesc,
549
+ mag: Math.min(dvAsc, dvDesc),
547
550
  node: (dvAsc <= dvDesc) ? "asc": "desc",
548
551
  };
549
552
  };
@@ -581,14 +584,14 @@ const planeChangePureInclinationDeltaV = (pv1, pv2)=>{
581
584
  // 1. Get position and velocity vectors and magnitudes.
582
585
  // Note that the magnitude of the final velocity for sat1 will be EQUAL
583
586
  // to this initial velocity magnitude of sat1!
584
- const r = multiply([pv1.position.x, pv1.position.y, pv1.position.z], 1000.0);
585
- const v = multiply([pv1.velocity.x, pv1.velocity.y, pv1.velocity.z], 1000.0);
587
+ const r = multiply([pv1.position.x, pv1.position.y, pv1.position.z], 1000);
588
+ const v = multiply([pv1.velocity.x, pv1.velocity.y, pv1.velocity.z], 1000);
586
589
 
587
590
  // Velocity Magnitude in m/s
588
591
  const vMag = norm(v);
589
592
 
590
- const r2 = multiply([pv2.position.x, pv2.position.y, pv2.position.z], 1000.0);
591
- const v2 = multiply([pv2.velocity.x, pv2.velocity.y, pv2.velocity.z], 1000.0);
593
+ const r2 = multiply([pv2.position.x, pv2.position.y, pv2.position.z], 1000);
594
+ const v2 = multiply([pv2.velocity.x, pv2.velocity.y, pv2.velocity.z], 1000);
592
595
 
593
596
  // 2. Compute the Keplerian Elements of both satellites.
594
597
  const el = cartesianToKeplerian(r, v);
@@ -613,7 +616,7 @@ const planeChangePureInclinationDeltaV = (pv1, pv2)=>{
613
616
  const dvAsc = 2* vMag * Math.cos(gammaAscending) * Math.sin(incRad/2);
614
617
 
615
618
  // 4b. Compute the flight path angle and DV at descending node
616
- const fAtDesc = fAtAsc + 180.0;
619
+ const fAtDesc = fAtAsc + 180;
617
620
  const gammaDescending = Math.atan(
618
621
  el.e* Math.sin(fAtDesc*DEG2RAD)/(1+ el.e* Math.cos(fAtDesc*DEG2RAD)));
619
622
  const dvDesc = 2* vMag * Math.cos(gammaDescending) * Math.sin(incRad/2);
@@ -644,16 +647,14 @@ const planeChangePureInclinationDeltaV = (pv1, pv2)=>{
644
647
  dvC = (+1) * vMag * Math.cos(gammaDescending) * Math.sin(incRad);
645
648
  dvI = (-1) * vMag * Math.cos(gammaDescending) * (1 - Math.cos(incRad));
646
649
  }
650
+ } else if (Math.abs(dvAsc) <= Math.abs(dvDesc)) {
651
+ // Burn at ASC node is aligned with sat1 cross-track
652
+ dvC = (+1) * vMag * Math.cos(gammaAscending) * Math.sin(incRad);
653
+ dvI = (-1) * vMag * Math.cos(gammaAscending) * (1 - Math.cos(incRad));
647
654
  } else {
648
- if (Math.abs(dvAsc) <= Math.abs(dvDesc)) {
649
- // Burn at ASC node is aligned with sat1 cross-track
650
- dvC = (+1) * vMag * Math.cos(gammaAscending) * Math.sin(incRad);
651
- dvI = (-1) * vMag * Math.cos(gammaAscending) * (1 - Math.cos(incRad));
652
- } else {
653
- // Burn at DESC node is opposite of the sat1 cross-track axis
654
- dvC = (-1) * vMag * Math.cos(gammaDescending) * Math.sin(incRad);
655
- dvI = (-1) * vMag * Math.cos(gammaDescending) * (1 - Math.cos(incRad));
656
- }
655
+ // Burn at DESC node is opposite of the sat1 cross-track axis
656
+ dvC = (-1) * vMag * Math.cos(gammaDescending) * Math.sin(incRad);
657
+ dvI = (-1) * vMag * Math.cos(gammaDescending) * (1 - Math.cos(incRad));
657
658
  }
658
659
 
659
660
  // 5. Return the RSW components of the required burn!
@@ -662,7 +663,7 @@ const planeChangePureInclinationDeltaV = (pv1, pv2)=>{
662
663
  r: 0,
663
664
  i: dvI,
664
665
  c: dvC,
665
- mag: (dvAsc <= dvDesc) ? dvAsc: dvDesc,
666
+ mag: Math.min(dvAsc, dvDesc),
666
667
  node: (dvAsc <= dvDesc) ? "asc": "desc",
667
668
  };
668
669
  };
@@ -686,10 +687,7 @@ const angleBetweenPlanes = (pv1, pv2) => {
686
687
  [pv1.position.x, pv1.position.y, pv1.position.z],
687
688
  [pv1.velocity.x, pv1.velocity.y, pv1.velocity.z],
688
689
  );
689
- const cross1mag = Math.sqrt(
690
- cross1[0] * cross1[0]
691
- + cross1[1] * cross1[1]
692
- + cross1[2] * cross1[2]);
690
+ const cross1mag = Math.hypot(cross1[0], cross1[1], cross1[2]);
693
691
 
694
692
  const cross1Norm = {
695
693
  x: cross1[0] / cross1mag,
@@ -701,10 +699,7 @@ const angleBetweenPlanes = (pv1, pv2) => {
701
699
  [pv2.position.x, pv2.position.y, pv2.position.z],
702
700
  [pv2.velocity.x, pv2.velocity.y, pv2.velocity.z],
703
701
  );
704
- const cross2Mag = Math.sqrt(
705
- cross2[0] * cross2[0]
706
- + cross2[1] * cross2[1]
707
- + cross2[2] * cross2[2]);
702
+ const cross2Mag = Math.hypot(cross2[0], cross2[1], cross2[2]);
708
703
 
709
704
  const cross2Norm = {
710
705
  x: cross2[0] / cross2Mag,
@@ -721,7 +716,7 @@ const angleBetweenPlanes = (pv1, pv2) => {
721
716
  const clamped = Math.max(-1, Math.min(1, dotProducts));
722
717
 
723
718
  // Extract the angle from the dot products in degrees
724
- const angle = Math.acos(clamped) * (180.0 / Math.PI);
719
+ const angle = Math.acos(clamped) * (180 / Math.PI);
725
720
 
726
721
  // Round result to 3 decimal points and return
727
722
  return Math.round(angle * 1000) / 1000;
@@ -829,7 +824,7 @@ const doesLineSegmentSphereIntersect = (linePoint0, linePoint1, circleCenter, ci
829
824
  return Math.abs(distanceSquared - circleRadius * circleRadius) < Number.EPSILON;
830
825
  }
831
826
 
832
- const b = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
827
+ const b = 2 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
833
828
  const c = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy
834
829
  + pz * pz - 2 * pz * cz + cz * cz - circleRadius * circleRadius;
835
830
 
@@ -841,8 +836,8 @@ const doesLineSegmentSphereIntersect = (linePoint0, linePoint1, circleCenter, ci
841
836
  }
842
837
 
843
838
  const sqrtD = Math.sqrt(d);
844
- const t1 = (-b - sqrtD) / (2.0 * a);
845
- const t2 = (-b + sqrtD) / (2.0 * a);
839
+ const t1 = (-b - sqrtD) / (2 * a);
840
+ const t2 = (-b + sqrtD) / (2 * a);
846
841
 
847
842
  // Check if either intersection point lies within the line segment bounds [0,1]
848
843
  return (t1 >= 0 && t1 <= 1) || (t2 >= 0 && t2 <= 1);
@@ -946,13 +941,13 @@ const getSunDirection = (time) => {
946
941
  const seconds = time.getUTCSeconds();
947
942
  const JD
948
943
  = 367 * year
949
- - Math.floor((7.0 * (year + Math.floor((month + 9.0) / 12.0))) / 4.0)
950
- + Math.floor((275.0 * month) / 9.0)
944
+ - Math.floor((7 * (year + Math.floor((month + 9) / 12))) / 4)
945
+ + Math.floor((275 * month) / 9)
951
946
  + day
952
947
  + 1721013.5
953
- + hour / 24.0
954
- + minute / 1440.0
955
- + seconds / 86400.0;
948
+ + hour / 24
949
+ + minute / 1440
950
+ + seconds / 86400;
956
951
  const UT1 = (JD - 2451545) / 36525;
957
952
  const longMSUN = 280.4606184 + 36000.77005361 * UT1;
958
953
  const mSUN = 357.5277233 + 35999.05034 * UT1;
@@ -1111,8 +1106,21 @@ const estimateSlantRange = (obTime, ra, dec, senLat, senLon, senAltKm) => {
1111
1106
  (Math.pow(a, 2) + Math.pow(b, 2) - Math.pow(delta, 2)), (-2*a*b), Math.pow(delta, 2));
1112
1107
 
1113
1108
  // The two solutions, only one is valid. Validity check is based on the fact that the sum of triangle angles is 180.
1114
- const gamma1 = Math.acos(roots[0]);
1115
- const gamma2 = Math.acos(roots[1]);
1109
+ const toRealRoot = (root) => {
1110
+ if (typeof root === "number") {
1111
+ return root;
1112
+ }
1113
+ if (root && typeof root.re === "number" && typeof root.im === "number") {
1114
+ // Accept numerically real roots produced as Complex with negligible imaginary part.
1115
+ if (Math.abs(root.im) <= 1e-12) {
1116
+ return root.re;
1117
+ }
1118
+ }
1119
+ throw new Error("Unable to compute GEO range from non-real polynomial root.");
1120
+ };
1121
+
1122
+ const gamma1 = Math.acos(toRealRoot(roots[0]));
1123
+ const gamma2 = Math.acos(toRealRoot(roots[1]));
1116
1124
 
1117
1125
  // Compute the sensor-satellite-earth angle
1118
1126
  const alpha = Math.sin(delta/a);
@@ -1244,8 +1252,7 @@ const GetResiduals = (obs, tle) => {
1244
1252
  return residuals; // Can't propegate TLE
1245
1253
  }
1246
1254
 
1247
- for (let i = 0; i < obs.length; i++) {
1248
- const ob = obs[i];
1255
+ for (const ob of obs) {
1249
1256
  const obTimeUtc = dtStrtoJsDt(ob.ObTime);
1250
1257
  const dt
1251
1258
  = (obTimeUtc.getTime() - dtStrtoJsDt(epochDate).getTime())
@@ -1321,7 +1328,7 @@ const GetElsetUdlFromTle = (
1321
1328
  // and we may be unsure of entering true or false for any reason.
1322
1329
  if (isBoolean(isUct)) {
1323
1330
  elset.uct = isUct;
1324
- } else if (isUct === null || typeof isUct === "undefined") {
1331
+ } else if (isUct === null || isUct === undefined) {
1325
1332
  // Do nothing, do not populate nor put null.
1326
1333
  } else {
1327
1334
  throw new Error("Input uct flag is not of type boolean.");
@@ -1353,7 +1360,7 @@ const GetElsetUdlFromTle = (
1353
1360
  const date = julianToGregorian(satrec.jdsatepoch);
1354
1361
  elset.epoch = date.toISOString();
1355
1362
 
1356
- elset.satNo = parseInt(satrec.satnum);
1363
+ elset.satNo = Number.parseInt(satrec.satnum);
1357
1364
 
1358
1365
  // Eccentricity
1359
1366
  elset.eccentricity = satrec.ecco;
@@ -1361,16 +1368,16 @@ const GetElsetUdlFromTle = (
1361
1368
  // Mean motion conversion from radians per minute to revs per day does not match
1362
1369
  // the value of mean motion on line 2 exactly! This is an issue of the satellite.js library
1363
1370
  // So we directly extract this number from line 2.
1364
- elset.meanMotion = parseFloat(l2.slice(52, 63));
1371
+ elset.meanMotion = Number.parseFloat(l2.slice(52, 63));
1365
1372
 
1366
1373
  // According to UDL, period field is the inverse of mean motion, in minutes!
1367
1374
  // This is added for convenience of the consumer. It is not needed for a successful POST operation.
1368
- elset.period = (1 / elset.meanMotion) * 24.0 * 60.0;
1375
+ elset.period = (1 / elset.meanMotion) * 24 * 60;
1369
1376
 
1370
1377
  // For convenience, we report the ephemeris Type, which is NOT automatically populated by UDL.
1371
1378
  // Again, this field is not mandatory and POST will succeed if it is ommitted. It is offered for convenience!
1372
1379
  // UDL suggests to use "SGP4" if orbital period < 225 minutes, and SDP4 otherwise (see ephemType field description in UDL Elset schema)
1373
- if (elset.period < 225.0) {
1380
+ if (elset.period < 225) {
1374
1381
  elset.ephemType = 0;
1375
1382
  } else {
1376
1383
  elset.ephemType = 3;
@@ -1401,7 +1408,7 @@ const GetElsetUdlFromTle = (
1401
1408
  elset.meanMotionDDot = satrec.nddot * (constants.xpdotp * 1440 * 1440);
1402
1409
 
1403
1410
  // Revolution number, parsed directly from line 2
1404
- elset.revNo = parseInt(l2.slice(63, 68));
1411
+ elset.revNo = Number.parseInt(l2.slice(63, 68));
1405
1412
 
1406
1413
  // sma
1407
1414
  elset.semiMajorAxis = (
@@ -1418,6 +1425,7 @@ const GetElsetUdlFromTle = (
1418
1425
  removeNullUndefined(elset);
1419
1426
  return elset;
1420
1427
  } catch (e) {
1428
+ console.error(e);
1421
1429
  // Return an empty object, which is guaranteed to be invalid
1422
1430
  // against UDL Elset_Ingested schema.
1423
1431
  return {};
@@ -1434,7 +1442,7 @@ const GetElsetUdlFromTle = (
1434
1442
  * Source: https://www.movable-type.co.uk/scripts/latlong.html
1435
1443
  */
1436
1444
  const distGeodetic = (lat1, lon1, lat2, lon2) => {
1437
- const R = WGS84_EARTH_EQUATORIAL_RADIUS_KM * 1000.0; // metres
1445
+ const R = WGS84_EARTH_EQUATORIAL_RADIUS_KM * 1000; // metres
1438
1446
  const phi1 = lat1 * DEG2RAD; // φ1 in formula
1439
1447
  const phi2 = lat2 * DEG2RAD; // φ2 in formula
1440
1448
  const deltaPhi = (lat2 - lat1) * DEG2RAD; // Δφ in formula
@@ -1486,7 +1494,7 @@ const cartesianToKeplerian = (r, v) => {
1486
1494
  const zeta = 0.5 * Math.pow(norm(v), 2) - (mu / norm(r));
1487
1495
 
1488
1496
  if (zeta === 0) {throw new Error("Zeta cannot be zero.");}
1489
- if (Math.abs(1.0 - norm(e)) <= tol) {
1497
+ if (Math.abs(1 - norm(e)) <= tol) {
1490
1498
  throw new Error("Parabolic orbit conversion is not supported.");
1491
1499
  }
1492
1500
 
@@ -1509,7 +1517,7 @@ const cartesianToKeplerian = (r, v) => {
1509
1517
 
1510
1518
  // CASE 1: Non-circular, Inclined Orbit
1511
1519
  if (norm(e) >= 1E-11 && i >= 1E-11 && i <= Math.PI - 1E-11) {
1512
- if (norm(n) === 0.0) {
1520
+ if (norm(n) === 0) {
1513
1521
  throw new Error(`Cannot convert from Cartesian to Keplerian,
1514
1522
  line-of-nodes vector is a zero vector.`);
1515
1523
  }
@@ -1525,7 +1533,7 @@ const cartesianToKeplerian = (r, v) => {
1525
1533
  }
1526
1534
  // CASE 2: Non-circular, Equatorial Orbit
1527
1535
  if (norm(e) >= 1E-11 && (i < 1E-11 || i > Math.PI - 1E-11)) {
1528
- if (norm(e) === 0.0) {
1536
+ if (norm(e) === 0) {
1529
1537
  throw new Error(`Cannot convert from Cartesian to Keplerian,
1530
1538
  eccentricity is zero.`);
1531
1539
  }
@@ -1537,9 +1545,9 @@ const cartesianToKeplerian = (r, v) => {
1537
1545
 
1538
1546
  // For GMT-4446 fix (LOJ: 2014.03.21)
1539
1547
  if (i > Math.PI - 1E-11) {
1540
- w *= -1.0;
1548
+ w *= -1;
1541
1549
  }
1542
- if (w < 0.0) {
1550
+ if (w < 0) {
1543
1551
  w += 2 * Math.PI;
1544
1552
  }
1545
1553
 
@@ -1550,7 +1558,7 @@ const cartesianToKeplerian = (r, v) => {
1550
1558
  }
1551
1559
  // CASE 3: Circular, Inclined Orbit
1552
1560
  if (norm(e) < 1E-11 && i >= 1E-11 && i <= Math.PI - 1E-11) {
1553
- if (norm(n) === 0.0) {
1561
+ if (norm(n) === 0) {
1554
1562
  throw new Error(`Cannot convert from Cartesian to Keplerian,
1555
1563
  line-of-nodes vector is a zero vector.`);
1556
1564
  }
@@ -1573,14 +1581,14 @@ const cartesianToKeplerian = (r, v) => {
1573
1581
  if (r[1] < 0) {f = 2 * Math.PI - f;}
1574
1582
 
1575
1583
  // For GMT-4446 fix (LOJ: 2014.03.21)
1576
- if (i > Math.PI - 1E-11) {f *= -1.0;}
1577
- if (f < 0.0) {
1584
+ if (i > Math.PI - 1E-11) {f *= -1;}
1585
+ if (f < 0) {
1578
1586
  f += 2 * Math.PI;
1579
1587
  }
1580
1588
  }
1581
1589
 
1582
1590
  return {
1583
- a: a /1000.0, // km
1591
+ a: a /1000, // km
1584
1592
  e: norm(e),
1585
1593
  i: i * RAD2DEG, // deg
1586
1594
  raan: raan * RAD2DEG, // deg
@@ -1641,21 +1649,22 @@ const keplerianToCartesian = (elset, mu = 398600.4418) => {
1641
1649
  const sinPer = Math.sin(w);
1642
1650
 
1643
1651
  const r = {
1644
- x: 1000.0 * rad * (cosPerAnom * cosRaan - cosInc * sinPerAnom * sinRaan),
1645
- y: 1000.0 * rad * (cosPerAnom * sinRaan + cosInc * sinPerAnom * cosRaan),
1646
- z: 1000.0 * rad * sinPerAnom * sinInc,
1652
+ x: 1000 * rad * (cosPerAnom * cosRaan - cosInc * sinPerAnom * sinRaan),
1653
+ y: 1000 * rad * (cosPerAnom * sinRaan + cosInc * sinPerAnom * cosRaan),
1654
+ z: 1000 * rad * sinPerAnom * sinInc,
1647
1655
  };
1648
1656
 
1649
1657
  const v = {
1650
- x: 1000.0 * (sqrtGravP * cosAnomPlusE * (-sinPer * cosRaan - cosInc * sinRaan * cosPer)
1658
+ x: 1000 * (sqrtGravP * cosAnomPlusE * (-sinPer * cosRaan - cosInc * sinRaan * cosPer)
1651
1659
  - sqrtGravP * sinAnom * (cosPer * cosRaan - cosInc * sinRaan * sinPer)),
1652
- y: 1000.0 * (sqrtGravP * cosAnomPlusE * (-sinPer * sinRaan + cosInc * cosRaan * cosPer)
1660
+ y: 1000 * (sqrtGravP * cosAnomPlusE * (-sinPer * sinRaan + cosInc * cosRaan * cosPer)
1653
1661
  - sqrtGravP * sinAnom * (cosPer * sinRaan + cosInc * cosRaan * sinPer)),
1654
- z: 1000.0 * (sqrtGravP * (cosAnomPlusE * sinInc * cosPer - sinAnom * sinInc * sinPer)),
1662
+ z: 1000 * (sqrtGravP * (cosAnomPlusE * sinInc * cosPer - sinAnom * sinInc * sinPer)),
1655
1663
  };
1656
1664
 
1657
1665
  return {r, v};
1658
1666
  } catch (err) {
1667
+ console.error(err);
1659
1668
  return {};
1660
1669
  }
1661
1670
  };
@@ -1663,8 +1672,8 @@ const keplerianToCartesian = (elset, mu = 398600.4418) => {
1663
1672
  const cartesianToElsetElements = (pv, epoch) => {
1664
1673
  // sma, eccentricity, inclination, raan, argp, trueAnomaly
1665
1674
  const kepl = cartesianToKeplerian(
1666
- multiply(posToArray(pv.position), 1000.0), // km to m
1667
- multiply(posToArray(pv.velocity), 1000.0), // km/s to m/s
1675
+ multiply(posToArray(pv.position), 1000), // km to m
1676
+ multiply(posToArray(pv.velocity), 1000), // km/s to m/s
1668
1677
  );
1669
1678
 
1670
1679
  const elset = {
@@ -1677,7 +1686,7 @@ const cartesianToElsetElements = (pv, epoch) => {
1677
1686
 
1678
1687
  // Mean motion in radians per second
1679
1688
  const mu = 3.986004418e14; // (m^3)/(s^2) WGS-84 Earth Mu
1680
- const meanMotion = Math.sqrt(mu/Math.pow((elset.SemiMajorAxis*1000.0), 3));
1689
+ const meanMotion = Math.sqrt(mu/Math.pow((elset.SemiMajorAxis*1000), 3));
1681
1690
 
1682
1691
  elset.MeanMotion = meanMotion / (2*Math.PI) * 60 * 60 * 24; // rads/s to revs per day
1683
1692
 
@@ -1867,8 +1876,8 @@ const getGeoRpoData = (line1, line2, sats, startTime, endTime, lonTime) => {
1867
1876
  aResult.longitude = (sLonAndDrift.longitude + 360) % 360; // Normalize to 0-360
1868
1877
 
1869
1878
  const lonDiff = Math.abs(
1870
- (pLonAndDrift.longitude + 360.0) % 360
1871
- - (sLonAndDrift.longitude + 360.0) % 360.0,
1879
+ (pLonAndDrift.longitude + 360) % 360
1880
+ - (sLonAndDrift.longitude + 360) % 360,
1872
1881
  );
1873
1882
  // To ensure that the smallest "short-way" lon diff is considered
1874
1883
  aResult.lonDiff = Math.min(lonDiff, 360 - lonDiff);
@@ -1948,7 +1957,7 @@ const getGeoShadowZones = (time, accuracySecondsDeg=0.00416*100) => {
1948
1957
  // Compare with the previous eclipse state
1949
1958
  if (res[i].ecl!==res[i-1].ecl) {
1950
1959
  // Close the previous zone
1951
- ints[ints.length-1].stopDeg = res[i-1].geolon;
1960
+ ints.at(-1).stopDeg = res[i-1].geolon;
1952
1961
 
1953
1962
  // Open a new zone
1954
1963
  ints.push({
@@ -1971,16 +1980,16 @@ const getGeoShadowZones = (time, accuracySecondsDeg=0.00416*100) => {
1971
1980
  };
1972
1981
  }
1973
1982
 
1974
- ints[0].startDeg = ints[ints.length-1].startDeg;
1983
+ ints[0].startDeg = ints.at(-1).startDeg;
1975
1984
  ints.pop();
1976
1985
 
1977
1986
  if (
1978
1987
  ints.filter((x)=>x.ecl === "UMBRA").length===0
1979
- && ints.filter((x)=>x.ecl === "PENUMBRA").length>0) {
1988
+ && ints.some((x)=>x.ecl === "PENUMBRA")) {
1980
1989
  // If there's no umbra but penumbra exists, return the perumbra values
1981
1990
 
1982
1991
  // Extract the penumbra interval. In the absence of umbra, a single penumbra interval should exist.
1983
- const penumbraInt = ints.filter((x)=>x.ecl === "PENUMBRA")[0];
1992
+ const penumbraInt = ints.find((x)=>x.ecl === "PENUMBRA");
1984
1993
  return {
1985
1994
  penStartWestLon: wrapToRange(penumbraInt.startDeg, 0, 360),
1986
1995
  penStartEastLon: wrapToRange(penumbraInt.stopDeg, 0, 360),
@@ -1988,7 +1997,7 @@ const getGeoShadowZones = (time, accuracySecondsDeg=0.00416*100) => {
1988
1997
  } else {
1989
1998
  // If sun, umbra, penumbra intervals exist
1990
1999
 
1991
- const umbra = ints.filter((x)=>x.ecl === "UMBRA")[0];
2000
+ const umbra = ints.find((x)=>x.ecl === "UMBRA");
1992
2001
 
1993
2002
  const umbraStart360 = wrapToRange(umbra.startDeg, 0, 360);
1994
2003
  const umbraStop360 = wrapToRange(umbra.stopDeg, 0, 360);
@@ -2019,8 +2028,8 @@ const getGeoShadowZones = (time, accuracySecondsDeg=0.00416*100) => {
2019
2028
  * @param {Number} accuracySeconds The accuracy of the calulations, defaults to 1 sec. The higher, the faster.
2020
2029
  * @return {Array} An array of objects, each of which represents a contiguous interval of sunlight, penumbra, or umbra.
2021
2030
  */
2022
- const getGeoLightIntervals = (time, durationSeconds=86400, accuracySeconds=10.0) => {
2023
- const endTime = new Date(time.getTime() + 1000.0*durationSeconds);
2031
+ const getGeoLightIntervals = (time, durationSeconds=86400, accuracySeconds=10) => {
2032
+ const endTime = new Date(time.getTime() + 1000*durationSeconds);
2024
2033
  // Create an artificial satellite on GEO
2025
2034
  const satrec = twoline2satrec(
2026
2035
  "1 00000U 00000A 24079.98445361 -.00000000 00000-0 -00000-0 0 00000",
@@ -2048,7 +2057,7 @@ const getGeoLightIntervals = (time, durationSeconds=86400, accuracySeconds=10.0)
2048
2057
  for (let i=1; i<=res.length-1; i++) {
2049
2058
  if (res[i].ecl!==res[i-1].ecl) {
2050
2059
  // Close the previous interval
2051
- ints[ints.length-1].end = res[i-1].t;
2060
+ ints.at(-1).end = res[i-1].t;
2052
2061
  // Create a new open interval
2053
2062
  ints.push({
2054
2063
  ecl: res[i].ecl,
@@ -2057,7 +2066,7 @@ const getGeoLightIntervals = (time, durationSeconds=86400, accuracySeconds=10.0)
2057
2066
  }
2058
2067
  }
2059
2068
  // Close the last interval
2060
- ints[ints.length-1].end = res[res.length-1].t;
2069
+ ints.at(-1).end = res.at(-1).t;
2061
2070
 
2062
2071
  return {
2063
2072
  ints: ints,
@@ -2174,9 +2183,9 @@ const calculateGeoCrossingTimes = async (propagateBetween, start, end, stepMs =
2174
2183
  const calculateNextApogeePerigeeTimesWithPropagation
2175
2184
  = async (pv, propagateTo, time, findApogee=true, findPerigee=true) => {
2176
2185
  const r = multiply([pv.position.x, pv.position.y, pv.position.z],
2177
- 1000.0);
2186
+ 1000);
2178
2187
  const v = multiply([pv.velocity.x, pv.velocity.y, pv.velocity.z],
2179
- 1000.0);
2188
+ 1000);
2180
2189
  const el = cartesianToKeplerian(r, v);
2181
2190
 
2182
2191
  // Compute Eccentric Anomaly from True Anomaly and Eccentricity
@@ -2187,7 +2196,7 @@ const calculateNextApogeePerigeeTimesWithPropagation
2187
2196
 
2188
2197
  // Mean motion in radians per second
2189
2198
  const mu = 3.986004418e14; // (m^3)/(s^2) WGS-84 Earth Mu
2190
- const n = Math.sqrt(mu/Math.pow((el.a*1000.0), 3));
2199
+ const n = Math.sqrt(mu/Math.pow((el.a*1000), 3));
2191
2200
 
2192
2201
  // Orbit Period
2193
2202
  const periodSecs = 2*Math.PI/n;
@@ -2204,7 +2213,7 @@ const calculateNextApogeePerigeeTimesWithPropagation
2204
2213
 
2205
2214
  // For next apoapsis, we check the true anomaly of the reference date
2206
2215
  let timeToNextApoapsisSecs;
2207
- if (el.f >= 180.0) {
2216
+ if (el.f >= 180) {
2208
2217
  // Satellite is past the apoapsis and before the next periapsis
2209
2218
  timeToNextApoapsisSecs = timeToNextPeriapsisSecs + periodSecs/2;
2210
2219
  } else {
@@ -2274,7 +2283,7 @@ const calculateNextApogeePerigeeTimes
2274
2283
  const satrec = twoline2satrec(line1, line2);
2275
2284
  const propagateTo = (t) => propagate(satrec, new Date(t));
2276
2285
  const pv = propagateTo(time);
2277
- return await calculateNextApogeePerigeeTimesWithPropagation(
2286
+ return calculateNextApogeePerigeeTimesWithPropagation(
2278
2287
  pv, propagateTo, time, findApogee, findPerigee,
2279
2288
  );
2280
2289
  };
@@ -2336,8 +2345,8 @@ const computePhaseDiff = (pSatRec, tSatRec, time) => {
2336
2345
  */
2337
2346
  const getOrbitalPeriod = (line2) => {
2338
2347
  // apparently mean motion should be obtained through TLE instead of satellite.js SatRec (see getElsetUdlFromTle)
2339
- const meanMotion = parseFloat(line2.slice(52, 63)); // revs per day
2340
- const period = (1 / meanMotion) * 24.0 * 60.0; // period in minutes
2348
+ const meanMotion = Number.parseFloat(line2.slice(52, 63)); // revs per day
2349
+ const period = (1 / meanMotion) * 24 * 60; // period in minutes
2341
2350
  return period;
2342
2351
  };
2343
2352
 
@@ -2444,8 +2453,8 @@ const getLeoWaterfallData = (elsets, startTime, endTime, stepMs = 10000) => {
2444
2453
  const ephem = prop(elset, segmentStart, segmentEnd, stepMs);
2445
2454
  satEphems[satIndex].push(...ephem.map((point, pointInd) => {
2446
2455
  const osculatingElements = cartesianToKeplerian(
2447
- multiply(posToArray(point.p), 1000.0), // km to m
2448
- multiply(posToArray(point.v), 1000.0), // km/s to m/s
2456
+ multiply(posToArray(point.p), 1000), // km to m
2457
+ multiply(posToArray(point.v), 1000), // km/s to m/s
2449
2458
  );
2450
2459
  return {
2451
2460
  ...point,
@@ -2539,9 +2548,9 @@ const getInterceptRendezvousMinDv = (sat1Tle, sat2Tle, startTime) =>{
2539
2548
  const sat1Pv = propagate(sat1Tle, new Date(startTime));
2540
2549
 
2541
2550
  // Sweep across 1 orbit period
2542
- const sat1Period = parseInt((120*Math.PI)/(sat1Tle.no));
2543
- const sat2Period = parseInt((120*Math.PI)/(sat2Tle.no));
2544
- const periodS = sat1Period > sat2Period ? sat1Period : sat2Period;
2551
+ const sat1Period = Number.parseInt((120*Math.PI)/(sat1Tle.no));
2552
+ const sat2Period = Number.parseInt((120*Math.PI)/(sat2Tle.no));
2553
+ const periodS = Math.max(sat1Period, sat2Period);
2545
2554
 
2546
2555
  for (let rev=0; rev < 10; rev++) {
2547
2556
  for (let dt=100; dt<=periodS; dt+=100) { // Seconds
@@ -2565,7 +2574,7 @@ const getInterceptRendezvousMinDv = (sat1Tle, sat2Tle, startTime) =>{
2565
2574
  }
2566
2575
 
2567
2576
  const currentVector = v1Mag <= vH1Mag ? deltaV1 : deltaVH1;
2568
- const currentNorm = v1Mag <= vH1Mag ? v1Mag : vH1Mag;
2577
+ const currentNorm = Math.min(v1Mag, vH1Mag);
2569
2578
 
2570
2579
  if (currentNorm < minDv) {
2571
2580
  revNum = rev;
@@ -2590,7 +2599,7 @@ const getInterceptRendezvousMinDv = (sat1Tle, sat2Tle, startTime) =>{
2590
2599
  }
2591
2600
  // As N increments, at some point either both or one of the two energy solutions will be NaN.
2592
2601
  // At that point, the N sweep can safely stop.
2593
- if (isNaN(v1Mag) || isNaN(vH1Mag)) {
2602
+ if (Number.isNaN(v1Mag) || Number.isNaN(vH1Mag)) {
2594
2603
  break;
2595
2604
  }
2596
2605
  }
@@ -2718,7 +2727,6 @@ const detectManeuverMinDv = (initialTLE, finalTLE) => {
2718
2727
 
2719
2728
  // Loop for N until NaN
2720
2729
  let minNorm = Infinity;
2721
- // let minIndex = -1;
2722
2730
  let minVector = [0, 0, 0];
2723
2731
  for (let i=0; i<10; i++) { // loop up to 10 revolutions, it is a safe upper limit to capture impulsive maneuvers
2724
2732
  const {v1, vH1} = lambertThomsonAlgorithm(r1, r2, dt, i, 0, v1Before, mu);
@@ -2735,16 +2743,15 @@ const detectManeuverMinDv = (initialTLE, finalTLE) => {
2735
2743
  }
2736
2744
 
2737
2745
  const currentVector = v1Mag <= vH1Mag ? deltaV1 : deltaVH1;
2738
- const currentNorm = v1Mag <= vH1Mag ? v1Mag : vH1Mag;
2746
+ const currentNorm = Math.min(v1Mag, vH1Mag);
2739
2747
 
2740
2748
  if (currentNorm < minNorm) {
2741
2749
  minNorm = currentNorm;
2742
- // minIndex = i;
2743
2750
  minVector = currentVector;
2744
2751
  }
2745
2752
  // As N increments, at some point either both or one of the two energy solutions will be NaN.
2746
2753
  // At that point, the N sweep can safely stop.
2747
- if (isNaN(v1Mag) || isNaN(vH1Mag)) {
2754
+ if (Number.isNaN(v1Mag) || Number.isNaN(vH1Mag)) {
2748
2755
  break;
2749
2756
  }
2750
2757
  }
@@ -2799,8 +2806,8 @@ const lambertThomsonAlgorithm
2799
2806
 
2800
2807
  // ----- Lines 2-5 -----
2801
2808
  let A = dot(r1, r2) / (r1Mag * r2Mag);
2802
- if (A > 1.0) {A = 1.0;}
2803
- if (A < -1.0) {A = -1.0;}
2809
+ if (A > 1) {A = 1;}
2810
+ if (A < -1) {A = -1;}
2804
2811
  let theta = Math.acos(A); // transfer angle
2805
2812
 
2806
2813
  // ----- Lines 6-8: Determine transfer direction -----
@@ -2813,26 +2820,26 @@ const lambertThomsonAlgorithm
2813
2820
  // ----- Lines 9-13 -----
2814
2821
  const c = norm(subtract(r2, r1)); // chord length
2815
2822
  const s = 0.5 * (r1Mag + r2Mag + c); // semiperimeter
2816
- const lambda = (1.0 / s) * Math.sqrt(r1Mag * r2Mag) * Math.cos(theta / 2.0);
2817
- const L = Math.pow((1 - lambda) / (1 + lambda), 2.0);
2818
- const mVal = 8 * mu * t * t / (Math.pow(s, 3.0) * Math.pow(1 + lambda, 6.0));
2823
+ const lambda = (1 / s) * Math.sqrt(r1Mag * r2Mag) * Math.cos(theta / 2);
2824
+ const L = Math.pow((1 - lambda) / (1 + lambda), 2);
2825
+ const mVal = 8 * mu * t * t / (Math.pow(s, 3) * Math.pow(1 + lambda, 6));
2819
2826
 
2820
2827
  // ----- Line 14: Initial x -----
2821
2828
  let x = (N > 0) ? (1 + 4 * L) : L;
2822
- let xdiff = 1.0;
2823
- let y = 0.0;
2829
+ let xdiff = 1;
2830
+ let y = 0;
2824
2831
 
2825
2832
  // ----- Lines 15-54: Iteration for x -----
2826
2833
  while (xdiff > 1e-6) {
2827
2834
  let h1; let h2;
2828
2835
  if (N > 0) {
2829
2836
  // ----- Lines 17-19: Multi-rev (N > 0) branch using Loechler's method -----
2830
- const numerator = Math.pow(L + x, 2.0);
2837
+ const numerator = Math.pow(L + x, 2);
2831
2838
  const denominator = 4 * x * x * (1 + 2 * x + L);
2832
2839
  const sqrtx = Math.sqrt(x);
2833
2840
  const commonTerm = ((N * Math.PI / 2 + Math.atan(sqrtx)) / sqrtx);
2834
2841
  // The bracketed term (Loechler p.30 (4.3))
2835
- const term1 = 3 * Math.pow(1 + x, 2.0) * commonTerm - (3 + 5 * x);
2842
+ const term1 = 3 * Math.pow(1 + x, 2) * commonTerm - (3 + 5 * x);
2836
2843
  h1 = (numerator / denominator) * term1;
2837
2844
 
2838
2845
  // ----- Line 19: h2 (Loechler p.31 (4.4)) -----
@@ -2840,7 +2847,7 @@ const lambertThomsonAlgorithm
2840
2847
  h2 = mVal / denominator * term2;
2841
2848
  } else {
2842
2849
  // ----- Lines 20-36: Single-rev branch -----
2843
- const eta = x / Math.pow(Math.sqrt(1 + x) + 1, 2.0);
2850
+ const eta = x / Math.pow(Math.sqrt(1 + x) + 1, 2);
2844
2851
  let bn = 3; let dn = 1; let un = 8 * (Math.sqrt(1 + x) + 1) / bn;
2845
2852
  let xi = un;
2846
2853
  let i = 1;
@@ -2862,16 +2869,16 @@ const lambertThomsonAlgorithm
2862
2869
  un = up * (dn - 1);
2863
2870
  xi += un;
2864
2871
  }
2865
- h1 = (Math.pow(L + x, 2.0) * (1 + 3 * x + xi))
2872
+ h1 = (Math.pow(L + x, 2) * (1 + 3 * x + xi))
2866
2873
  / ((1 + 2 * x + L) * (4 * x + xi * (3 + x)));
2867
2874
  h2 = mVal * (x - L + xi) / ((1 + 2 * x + L) * (4 * x + xi * (3 + x)));
2868
2875
  }
2869
2876
 
2870
2877
  // ----- Lines 38-39: Compute B and solve for K -----
2871
- const BVal = 27.0 * h2 / (4.0 * Math.pow(1 + h1, 3.0));
2872
- const uVal = BVal / (2.0 * (Math.sqrt(1 + BVal) + 1.0));
2878
+ const BVal = 27 * h2 / (4 * Math.pow(1 + h1, 3));
2879
+ const uVal = BVal / (2 * (Math.sqrt(1 + BVal) + 1));
2873
2880
 
2874
- const bn2 = 1.0; let dn2 = 1.0; let un2 = 1.0 / 3.0;
2881
+ const bn2 = 1; let dn2 = 1; let un2 = 1 / 3;
2875
2882
  let K = un2;
2876
2883
  let n = 0;
2877
2884
  let evenflag = 1;
@@ -2879,22 +2886,22 @@ const lambertThomsonAlgorithm
2879
2886
  const bp = bn2; const dp = dn2; const up = un2;
2880
2887
  let an;
2881
2888
  if (evenflag === 1) {
2882
- an = -2.0 * uVal * (3 * n + 2) * (6 * n + 1) / (9 * (4 * n + 1) * (4 * n + 3));
2889
+ an = -2 * uVal * (3 * n + 2) * (6 * n + 1) / (9 * (4 * n + 1) * (4 * n + 3));
2883
2890
  evenflag = 0;
2884
2891
  n++;
2885
2892
  } else {
2886
- an = -2.0 * uVal * (3 * n + 1) * (6 * n - 1) / 9.0 / (4 * n - 1) / (4 * n + 1);
2893
+ an = -2 * uVal * (3 * n + 1) * (6 * n - 1) / 9 / (4 * n - 1) / (4 * n + 1);
2887
2894
  evenflag = 1;
2888
2895
  }
2889
- dn2 = 1.0 / (1 - an * dp / bp / bn2);
2890
- un2 = up * (dn2 - 1.0);
2896
+ dn2 = 1 / (1 - an * dp / bp / bn2);
2897
+ un2 = up * (dn2 - 1);
2891
2898
  K += un2;
2892
2899
  }
2893
2900
 
2894
2901
  // ----- Line 50: Compute y -----
2895
- y = (1 + h1) / 3.0 * (2 + Math.sqrt(1 + BVal) / (1.0 + 2.0 * uVal * K * K));
2902
+ y = (1 + h1) / 3 * (2 + Math.sqrt(1 + BVal) / (1 + 2 * uVal * K * K));
2896
2903
  // ----- Line 51: Update xnew (Battin p.335 (7.113))
2897
- const xnew = Math.sqrt(Math.pow((1.0 - L)/2.0, 2.0) + mVal/(y*y)) - (1.0 + L)/2.0;
2904
+ const xnew = Math.sqrt(Math.pow((1 - L)/2, 2) + mVal/(y*y)) - (1 + L)/2;
2898
2905
  // ----- Line 52: Compute difference -----
2899
2906
  xdiff = Math.abs(xnew - x);
2900
2907
  // ----- Line 53: Update x -----
@@ -2902,14 +2909,14 @@ const lambertThomsonAlgorithm
2902
2909
  }
2903
2910
 
2904
2911
  // ----- Lines 55-57: Compute p and eccentricity -----
2905
- const pVal = 2 * r1Mag * r2Mag * y * y * Math.pow(1 + x, 2.0)
2906
- * Math.pow(Math.sin(theta / 2), 2.0)
2907
- / (mVal * s * Math.pow(1 + lambda, 2.0));
2912
+ const pVal = 2 * r1Mag * r2Mag * y * y * Math.pow(1 + x, 2)
2913
+ * Math.pow(Math.sin(theta / 2), 2)
2914
+ / (mVal * s * Math.pow(1 + lambda, 2));
2908
2915
  const eps = (r2Mag - r1Mag) / r1Mag;
2909
2916
  const eVal = Math.sqrt(
2910
- (Math.pow(eps, 2.0) + 4.0 * r2Mag / r1Mag
2911
- * Math.pow(Math.sin(theta / 2.0), 2.0) * Math.pow((L - x) / (L + x), 2.0))
2912
- / (Math.pow(eps, 2.0) + (4.0 * r2Mag / r1Mag) * Math.pow(Math.sin(theta / 2.0), 2.0)),
2917
+ (Math.pow(eps, 2) + 4 * r2Mag / r1Mag
2918
+ * Math.pow(Math.sin(theta / 2), 2) * Math.pow((L - x) / (L + x), 2))
2919
+ / (Math.pow(eps, 2) + (4 * r2Mag / r1Mag) * Math.pow(Math.sin(theta / 2), 2)),
2913
2920
  );
2914
2921
 
2915
2922
  // ----- Line 58: Call hodograph velocity algorithm -----
@@ -2922,7 +2929,7 @@ const lambertThomsonAlgorithm
2922
2929
  if (N > 0) {
2923
2930
  // Line 61:
2924
2931
  x = 1e-20;
2925
- xdiff = 1.0;
2932
+ xdiff = 1;
2926
2933
  while (xdiff > 1e-6) {
2927
2934
  // ----- Line 64: Compute h1 for high-energy solution (Loechler p.35 (5.5)) -----
2928
2935
  const h1He = (L + x) * (1 + 2 * x + L) / (2 * (L - x * x));
@@ -2931,18 +2938,18 @@ const lambertThomsonAlgorithm
2931
2938
  * ((L - x * x) * ((N * Math.PI / 2 + Math.atan(Math.sqrt(x)))
2932
2939
  / Math.sqrt(x)) - (L + x));
2933
2940
  // ----- Line 66: Compute B for high-energy solution (Loechler p.37 (5.9)) -----
2934
- const BHe = 27 * h2He / (4 * Math.pow(Math.sqrt(x) * (1 + h1He), 3.0));
2941
+ const BHe = 27 * h2He / (4 * Math.pow(Math.sqrt(x) * (1 + h1He), 3));
2935
2942
  let F;
2936
2943
  if (BHe < 0) {
2937
2944
  // ----- Line 68: Compute F for negative B -----
2938
- F = 2 * Math.cos(1.0 / 3.0 * Math.acos(Math.sqrt(BHe + 1)));
2945
+ F = 2 * Math.cos(1 / 3 * Math.acos(Math.sqrt(BHe + 1)));
2939
2946
  } else {
2940
2947
  // ----- Lines 70-71: Compute F for nonnegative B -----
2941
- const AHe = Math.pow(Math.sqrt(BHe) + Math.sqrt(BHe + 1), 1.0 / 3.0);
2948
+ const AHe = Math.pow(Math.sqrt(BHe) + Math.sqrt(BHe + 1), 1 / 3);
2942
2949
  F = AHe + 1 / AHe;
2943
2950
  }
2944
- // ----- Line 73: Compute y for high-energy solution (Loechler p.37 (5.10)) -----
2945
- const yHe = (2.0 / 3.0) * Math.sqrt(x) * (1 + h1He) * (Math.sqrt(BHe+1) / F + 1);
2951
+ // ----- Line 73: Compute y for high-energy solution (Loechler p.37 (5.1)) -----
2952
+ const yHe = (2 / 3) * Math.sqrt(x) * (1 + h1He) * (Math.sqrt(BHe+1) / F + 1);
2946
2953
  // ----- Line 74: Update xnew for high-energy solution (Loechler p.34 (5.3)) -----
2947
2954
  const temp = (mVal / (yHe * yHe)) - (1 + L);
2948
2955
  const xnewHe = 0.5 * (temp - Math.sqrt(temp * temp - 4 * L));
@@ -2950,10 +2957,10 @@ const lambertThomsonAlgorithm
2950
2957
  x = xnewHe;
2951
2958
  }
2952
2959
  // ----- Line 78: Compute semi-major axis a -----
2953
- const eVal = s * Math.pow(1 + lambda, 2.0) * (1 + x) * (L + x) / (8 * x);
2960
+ const eVal = s * Math.pow(1 + lambda, 2) * (1 + x) * (L + x) / (8 * x);
2954
2961
  // ----- Line 79: Compute p for high-energy solution -----
2955
- const pHe = 2 * r1Mag * r2Mag * Math.pow(Math.sin(theta / 2), 2.0) * (1 + x)
2956
- / (s * Math.pow(1 + lambda, 2.0) * (L + x));
2962
+ const pHe = 2 * r1Mag * r2Mag * Math.pow(Math.sin(theta / 2), 2) * (1 + x)
2963
+ / (s * Math.pow(1 + lambda, 2) * (L + x));
2957
2964
  // ----- Line 80: Compute eccentricity for high-energy solution -----
2958
2965
  const eHe = Math.sqrt(1 - pHe / eVal);
2959
2966
  // ----- Line 81: Compute high-energy velocities -----
@@ -2979,19 +2986,19 @@ const lambertThomsonAlgorithm
2979
2986
  */
2980
2987
  const hodographVelocityAlgorithm = (r1, r2, t, v1Minus, theta, p, e, mu) => {
2981
2988
  // Line 2: Define L180 (in meters)
2982
- const L180 = 1.0;
2989
+ const L180 = 1;
2983
2990
 
2984
2991
  const r1Mag = norm(r1);
2985
2992
  const r2Mag = norm(r2);
2986
2993
 
2987
2994
  // Line 3: A = mu*(1/r1 - 1/p)
2988
- const eVal = mu * (1.0 / r1Mag - 1.0 / p);
2995
+ const eVal = mu * (1 / r1Mag - 1 / p);
2989
2996
 
2990
2997
  // Line 4: B = (mu*e/p)^2 - A^2
2991
- const BVal = Math.pow(mu * e / p, 2.0) - (eVal * eVal);
2998
+ const BVal = Math.pow(mu * e / p, 2) - (eVal * eVal);
2992
2999
 
2993
3000
  // Line 5: if B <= 0 then x1 = 0 else x1 = -sqrt(B)
2994
- let x1 = (BVal <= 0) ? 0.0 : -Math.sqrt(BVal);
3001
+ let x1 = (BVal <= 0) ? 0 : -Math.sqrt(BVal);
2995
3002
 
2996
3003
  let nHat; // unit normal vector
2997
3004
 
@@ -3003,9 +3010,9 @@ const hodographVelocityAlgorithm = (r1, r2, t, v1Minus, theta, p, e, mu) => {
3003
3010
  nHat = [nHat.x, nHat.y, nHat.z];
3004
3011
 
3005
3012
  // Line 8: If the orbit is elliptical (e < 1)
3006
- if (e < 1.0) {
3013
+ if (e < 1) {
3007
3014
  // Line 9: P = 2π * sqrt( p^3 / [ mu * (1-e^2)^3 ] )
3008
- const P = 2 * Math.PI * Math.sqrt(Math.pow(p, 3.0) / (mu * Math.pow(1 - e * e, 3.0)));
3015
+ const P = 2 * Math.PI * Math.sqrt(Math.pow(p, 3) / (mu * Math.pow(1 - e * e, 3)));
3009
3016
  // Line 10: If (t mod P) > (P/2) then reverse x1
3010
3017
  const tMod = t % P;
3011
3018
  if (tMod > P / 2) {
@@ -3182,7 +3189,7 @@ const isSatInShadow = (epoch, satPos) => {
3182
3189
  const century = _century(epoch); // Convert date to Julian centuries since J2000 || equal to var tut1 in GetPosition()
3183
3190
 
3184
3191
  // Variables to solve for Sun Pos in ___ frame
3185
- const lamM = (280.460 + 36000.771*century % 360) * DEG2RAD;
3192
+ const lamM = (280.46 + 36000.771*century % 360) * DEG2RAD;
3186
3193
  const M = (357.5291092 + 35999.05034*century % 360) * DEG2RAD;
3187
3194
  const lamEc = (((lamM * RAD2DEG)
3188
3195
  + 1.914666471 * Math.sin(M)
@@ -3229,14 +3236,14 @@ const isSatInShadow = (epoch, satPos) => {
3229
3236
  };
3230
3237
 
3231
3238
  // Convert Sun Pos from GCRF to J2000
3232
- const xi0 = -0.0166170 * arcsec2rad;
3239
+ const xi0 = -0.016617 * arcsec2rad;
3233
3240
  const eta0 = -0.0068192 * arcsec2rad;
3234
- const da0 = -0.01460 * arcsec2rad;
3241
+ const da0 = -0.0146 * arcsec2rad;
3235
3242
 
3236
3243
  const gcrf2j2000 = [
3237
- [1.0 - 0.5*(-da0*-da0 + xi0*xi0), da0, -xi0],
3238
- [-da0, 1.0 - 0.5*(-da0*-da0 + eta0*eta0), -eta0],
3239
- [xi0, eta0, 1.0 - 0.5*(eta0*eta0 + xi0*xi0)],
3244
+ [1 - 0.5*(-da0*-da0 + xi0*xi0), da0, -xi0],
3245
+ [-da0, 1 - 0.5*(-da0*-da0 + eta0*eta0), -eta0],
3246
+ [xi0, eta0, 1 - 0.5*(eta0*eta0 + xi0*xi0)],
3240
3247
  ];
3241
3248
 
3242
3249
  const sunVecJ2000 = multiply(gcrf2j2000, posToArray(sunVecGCRF)); // Sun Position in J2000
@@ -3277,15 +3284,26 @@ const isSatInShadow = (epoch, satPos) => {
3277
3284
  return shadowType; // return the shadow type
3278
3285
  };
3279
3286
 
3280
- import * as CONSTANTS from "./constants.js";
3281
- export {CONSTANTS};
3282
- export {REGIMES,
3283
- julianToGregorian,
3287
+ export * as CONSTANTS from "./constants.js";
3288
+ export {REGIMES} from "./constants.js";
3289
+ export {julianToGregorian, multiplyVector, dist} from "./utils.js";
3290
+ export {
3291
+ twoline2satrec,
3292
+ sgp4,
3293
+ gstime,
3294
+ eciToGeodetic,
3295
+ eciToEcf,
3296
+ ecfToLookAngles,
3297
+ degreesToRadians,
3298
+ radiansToDegrees,
3299
+ degreesLong,
3300
+ degreesLat,
3301
+ propagate,
3302
+ } from "satellite.js";
3303
+ export {
3284
3304
  calcRegime,
3285
3305
  altToRegime,
3286
3306
  cartesianToRIC,
3287
- multiplyVector,
3288
- dist,
3289
3307
  angleBetween3DCoords,
3290
3308
  prop,
3291
3309
  propGeodetic,
@@ -3298,7 +3316,6 @@ export {REGIMES,
3298
3316
  distGeodetic,
3299
3317
  getSemiMajorAxis,
3300
3318
  angleBetweenPlanes,
3301
- propagate,
3302
3319
  planeChangeDeltaV,
3303
3320
  planeChangePureInclinationDeltaV,
3304
3321
  cartesianToKeplerian,
@@ -3330,21 +3347,10 @@ export {REGIMES,
3330
3347
  isSatInShadow,
3331
3348
  calculateGeoCrossingTimes,
3332
3349
  tryPropagateSatrec,
3333
- twoline2satrec,
3334
- sgp4,
3335
- gstime,
3336
- eciToGeodetic,
3337
- eciToEcf,
3338
- ecfToLookAngles,
3339
- degreesToRadians,
3340
- radiansToDegrees,
3341
- degreesLong,
3342
- degreesLat,
3343
3350
  };
3344
3351
  export const raDecToGeodetic = RaDecToGeodetic;
3345
3352
  export const getResiduals = GetResiduals;
3346
3353
  export const raDecToAzEl = RaDecToAzEl;
3347
3354
  export const azElToRaDec = AzElToRaDec;
3348
3355
  export const getElsetUdlFromTle = GetElsetUdlFromTle;
3349
- import * as satjs from "satellite.js";
3350
- export {satjs};
3356
+ export * as satjs from "satellite.js";