satkit 0.9.0__tar.gz → 0.9.2__tar.gz

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.
Files changed (193) hide show
  1. {satkit-0.9.0 → satkit-0.9.2}/.github/workflows/build.yml +6 -6
  2. satkit-0.9.2/.github/workflows/cargo-publish.yml +35 -0
  3. {satkit-0.9.0 → satkit-0.9.2}/.github/workflows/wheels.yml +34 -6
  4. {satkit-0.9.0 → satkit-0.9.2}/CHANGES.md +12 -0
  5. {satkit-0.9.0 → satkit-0.9.2}/Cargo.toml +5 -4
  6. {satkit-0.9.0 → satkit-0.9.2}/PKG-INFO +15 -10
  7. {satkit-0.9.0 → satkit-0.9.2}/README.md +14 -9
  8. {satkit-0.9.0 → satkit-0.9.2}/pyproject.toml +3 -1
  9. {satkit-0.9.0 → satkit-0.9.2}/python/requirements.txt +1 -1
  10. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/_version.py +2 -2
  11. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/satkit.pyi +28 -0
  12. {satkit-0.9.0 → satkit-0.9.2}/python/satkit.egg-info/PKG-INFO +15 -10
  13. {satkit-0.9.0 → satkit-0.9.2}/python/satkit.egg-info/SOURCES.txt +3 -0
  14. {satkit-0.9.0 → satkit-0.9.2}/python/test/test.py +79 -0
  15. {satkit-0.9.0 → satkit-0.9.2}/src/earth_orientation_params.rs +8 -8
  16. {satkit-0.9.0 → satkit-0.9.2}/src/frametransform/mod.rs +16 -16
  17. {satkit-0.9.0 → satkit-0.9.2}/src/frametransform/qcirs2gcrs.rs +4 -4
  18. {satkit-0.9.0 → satkit-0.9.2}/src/itrfcoord.rs +37 -8
  19. {satkit-0.9.0 → satkit-0.9.2}/src/jplephem.rs +21 -26
  20. {satkit-0.9.0 → satkit-0.9.2}/src/lib.rs +6 -1
  21. {satkit-0.9.0 → satkit-0.9.2}/src/lpephem/moon.rs +16 -10
  22. {satkit-0.9.0 → satkit-0.9.2}/src/lpephem/planets.rs +5 -3
  23. {satkit-0.9.0 → satkit-0.9.2}/src/lpephem/sun.rs +13 -8
  24. {satkit-0.9.0 → satkit-0.9.2}/src/nrlmsise.rs +9 -5
  25. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/drag.rs +3 -3
  26. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/precomputed.rs +8 -4
  27. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/propagator.rs +40 -19
  28. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/satstate.rs +69 -9
  29. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/settings.rs +2 -2
  30. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pydensity.rs +2 -2
  31. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyitrfcoord.rs +13 -13
  32. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pynrlmsise.rs +7 -1
  33. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/sgp4_impl.rs +23 -18
  34. {satkit-0.9.0 → satkit-0.9.2}/src/spaceweather.rs +6 -4
  35. satkit-0.9.2/src/time/chrono.rs +165 -0
  36. {satkit-0.9.0 → satkit-0.9.2}/src/time/duration.rs +7 -0
  37. {satkit-0.9.0 → satkit-0.9.2}/src/time/mod.rs +5 -0
  38. satkit-0.9.2/src/time/timelike.rs +56 -0
  39. {satkit-0.9.0 → satkit-0.9.2}/.gitignore +0 -0
  40. {satkit-0.9.0 → satkit-0.9.2}/.readthedocs.yaml +0 -0
  41. {satkit-0.9.0 → satkit-0.9.2}/CONTRIBUTING.md +0 -0
  42. {satkit-0.9.0 → satkit-0.9.2}/LICENSE +0 -0
  43. {satkit-0.9.0 → satkit-0.9.2}/MANIFEST.in +0 -0
  44. {satkit-0.9.0 → satkit-0.9.2}/build.rs +0 -0
  45. {satkit-0.9.0 → satkit-0.9.2}/extern/nrlmsise/DOCUMENTATION +0 -0
  46. {satkit-0.9.0 → satkit-0.9.2}/extern/nrlmsise/nrlmsise-00.c +0 -0
  47. {satkit-0.9.0 → satkit-0.9.2}/extern/nrlmsise/nrlmsise-00.h +0 -0
  48. {satkit-0.9.0 → satkit-0.9.2}/extern/nrlmsise/nrlmsise-00_data.c +0 -0
  49. {satkit-0.9.0 → satkit-0.9.2}/python/Pipfile +0 -0
  50. {satkit-0.9.0 → satkit-0.9.2}/python/docs/Makefile +0 -0
  51. {satkit-0.9.0 → satkit-0.9.2}/python/docs/jsdoc_config.json +0 -0
  52. {satkit-0.9.0 → satkit-0.9.2}/python/docs/jsdoc_plugin.js +0 -0
  53. {satkit-0.9.0 → satkit-0.9.2}/python/docs/make.bat +0 -0
  54. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/TLE.md +0 -0
  55. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/_static/density_vs_solar_cycle.svg +0 -0
  56. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/_static/force_vs_altitude.svg +0 -0
  57. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/_static/theme_mods.css +0 -0
  58. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/consts.md +0 -0
  59. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/density.md +0 -0
  60. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/earthgravity.md +0 -0
  61. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/frametransform.md +0 -0
  62. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/itrfcoord.md +0 -0
  63. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/jplephem.md +0 -0
  64. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/kepler.md +0 -0
  65. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/quaternion.md +0 -0
  66. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/satprop.md +0 -0
  67. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/satstate.md +0 -0
  68. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/time.md +0 -0
  69. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/tle.md +0 -0
  70. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/api/utils.md +0 -0
  71. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/conf.py +0 -0
  72. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/datafiles.md +0 -0
  73. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/density.md +0 -0
  74. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/Eclipse.ipynb +0 -0
  75. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/High Precision Propagation.ipynb +0 -0
  76. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/ITRF Coordinates.ipynb +0 -0
  77. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/Orbital Mean-Element Message.ipynb +0 -0
  78. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/Plots.ipynb +0 -0
  79. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/Satellite Ground Contacts.ipynb +0 -0
  80. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/TLE Fitting.ipynb +0 -0
  81. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/Two-Line Element Set.ipynb +0 -0
  82. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/examples/riseset.ipynb +0 -0
  83. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/frametransform.md +0 -0
  84. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/index.md +0 -0
  85. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/install.md +0 -0
  86. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/itrfcoord.md +0 -0
  87. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/quaternion.md +0 -0
  88. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/references.md +0 -0
  89. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/satprop.md +0 -0
  90. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/satstate.md +0 -0
  91. {satkit-0.9.0 → satkit-0.9.2}/python/docs/source/time.md +0 -0
  92. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/__init__.py +0 -0
  93. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/__init__.pyi +0 -0
  94. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/density.pyi +0 -0
  95. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/frametransform.pyi +0 -0
  96. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/jplephem.pyi +0 -0
  97. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/moon.pyi +0 -0
  98. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/planets.pyi +0 -0
  99. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/py.typed +0 -0
  100. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/sun.pyi +0 -0
  101. {satkit-0.9.0 → satkit-0.9.2}/python/satkit/utils.pyi +0 -0
  102. {satkit-0.9.0 → satkit-0.9.2}/python/satkit.egg-info/dependency_links.txt +0 -0
  103. {satkit-0.9.0 → satkit-0.9.2}/python/satkit.egg-info/requires.txt +0 -0
  104. {satkit-0.9.0 → satkit-0.9.2}/python/satkit.egg-info/top_level.txt +0 -0
  105. {satkit-0.9.0 → satkit-0.9.2}/python/test/download_data.py +0 -0
  106. {satkit-0.9.0 → satkit-0.9.2}/python/test/download_from_json.py +0 -0
  107. {satkit-0.9.0 → satkit-0.9.2}/python/test/download_testvecs.py +0 -0
  108. {satkit-0.9.0 → satkit-0.9.2}/python/test/sp3file.py +0 -0
  109. {satkit-0.9.0 → satkit-0.9.2}/setup.cfg +0 -0
  110. {satkit-0.9.0 → satkit-0.9.2}/src/consts.rs +0 -0
  111. {satkit-0.9.0 → satkit-0.9.2}/src/earthgravity.rs +0 -0
  112. {satkit-0.9.0 → satkit-0.9.2}/src/filters/mod.rs +0 -0
  113. {satkit-0.9.0 → satkit-0.9.2}/src/filters/ukf.rs +0 -0
  114. {satkit-0.9.0 → satkit-0.9.2}/src/frames.rs +0 -0
  115. {satkit-0.9.0 → satkit-0.9.2}/src/frametransform/ierstable.rs +0 -0
  116. {satkit-0.9.0 → satkit-0.9.2}/src/kepler.rs +0 -0
  117. {satkit-0.9.0 → satkit-0.9.2}/src/lpephem/mod.rs +0 -0
  118. {satkit-0.9.0 → satkit-0.9.2}/src/mathtypes.rs +0 -0
  119. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/mod.rs +0 -0
  120. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkf45.rs +0 -0
  121. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkts54.rs +0 -0
  122. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv65.rs +0 -0
  123. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv65_table.rs +0 -0
  124. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv87.rs +0 -0
  125. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv87_table.rs +0 -0
  126. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98.rs +0 -0
  127. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_efficient.rs +0 -0
  128. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_efficient_table.rs +0 -0
  129. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_nointerp.rs +0 -0
  130. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_nointerp_table.rs +0 -0
  131. {satkit-0.9.0 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_table.rs +0 -0
  132. {satkit-0.9.0 → satkit-0.9.2}/src/ode/mod.rs +0 -0
  133. {satkit-0.9.0 → satkit-0.9.2}/src/ode/nalgebra_bindings.rs +0 -0
  134. {satkit-0.9.0 → satkit-0.9.2}/src/ode/ode_tests.rs +0 -0
  135. {satkit-0.9.0 → satkit-0.9.2}/src/ode/rk_adaptive.rs +0 -0
  136. {satkit-0.9.0 → satkit-0.9.2}/src/ode/rk_adaptive_settings.rs +0 -0
  137. {satkit-0.9.0 → satkit-0.9.2}/src/ode/rk_explicit.rs +0 -0
  138. {satkit-0.9.0 → satkit-0.9.2}/src/ode/types.rs +0 -0
  139. {satkit-0.9.0 → satkit-0.9.2}/src/omm/mod.rs +0 -0
  140. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/mod.rs +0 -0
  141. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/point_gravity.rs +0 -0
  142. {satkit-0.9.0 → satkit-0.9.2}/src/orbitprop/satproperties.rs +0 -0
  143. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/mod.rs +0 -0
  144. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/mod_utils.rs +0 -0
  145. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyconsts.rs +0 -0
  146. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyduration.rs +0 -0
  147. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyframes.rs +0 -0
  148. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyframetransform.rs +0 -0
  149. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pygravity.rs +0 -0
  150. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyinstant.rs +0 -0
  151. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyjplephem.rs +0 -0
  152. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pykepler.rs +0 -0
  153. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pylpephem_moon.rs +0 -0
  154. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pylpephem_planets.rs +0 -0
  155. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pylpephem_sun.rs +0 -0
  156. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pympsuccess.rs +0 -0
  157. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pypropagate.rs +0 -0
  158. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pypropresult.rs +0 -0
  159. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pypropsettings.rs +0 -0
  160. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyquaternion.rs +0 -0
  161. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pysatproperties.rs +0 -0
  162. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pysatstate.rs +0 -0
  163. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pysgp4.rs +0 -0
  164. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pysolarsystem.rs +0 -0
  165. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pytle.rs +0 -0
  166. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyukf.rs +0 -0
  167. {satkit-0.9.0 → satkit-0.9.2}/src/pybindings/pyutils.rs +0 -0
  168. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/dpper.rs +0 -0
  169. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/dscom.rs +0 -0
  170. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/dsinit.rs +0 -0
  171. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/dspace.rs +0 -0
  172. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/getgravconst.rs +0 -0
  173. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/initl.rs +0 -0
  174. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/mod.rs +0 -0
  175. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/satrec.rs +0 -0
  176. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/sgp4_lowlevel.rs +0 -0
  177. {satkit-0.9.0 → satkit-0.9.2}/src/sgp4/sgp4init.rs +0 -0
  178. {satkit-0.9.0 → satkit-0.9.2}/src/solarsystem.rs +0 -0
  179. {satkit-0.9.0 → satkit-0.9.2}/src/time/instant.rs +0 -0
  180. {satkit-0.9.0 → satkit-0.9.2}/src/time/instant_err.rs +0 -0
  181. {satkit-0.9.0 → satkit-0.9.2}/src/time/instant_ops.rs +0 -0
  182. {satkit-0.9.0 → satkit-0.9.2}/src/time/instantparse.rs +0 -0
  183. {satkit-0.9.0 → satkit-0.9.2}/src/time/tests.rs +0 -0
  184. {satkit-0.9.0 → satkit-0.9.2}/src/time/timescale.rs +0 -0
  185. {satkit-0.9.0 → satkit-0.9.2}/src/time/weekday.rs +0 -0
  186. {satkit-0.9.0 → satkit-0.9.2}/src/tle/fitting.rs +0 -0
  187. {satkit-0.9.0 → satkit-0.9.2}/src/tle/mod.rs +0 -0
  188. {satkit-0.9.0 → satkit-0.9.2}/src/utils/datadir.rs +0 -0
  189. {satkit-0.9.0 → satkit-0.9.2}/src/utils/download.rs +0 -0
  190. {satkit-0.9.0 → satkit-0.9.2}/src/utils/mod.rs +0 -0
  191. {satkit-0.9.0 → satkit-0.9.2}/src/utils/pypackage.rs +0 -0
  192. {satkit-0.9.0 → satkit-0.9.2}/src/utils/test.rs +0 -0
  193. {satkit-0.9.0 → satkit-0.9.2}/src/utils/update_data.rs +0 -0
@@ -64,7 +64,7 @@ jobs:
64
64
  run: |
65
65
  python -m pip install requests
66
66
  python python/test/download_data.py ${{matrix.data_path}}
67
-
67
+
68
68
 
69
69
  # Try to recover satkit test vectors from cache
70
70
  - name: Cache Satkit Test Vectors
@@ -79,7 +79,7 @@ jobs:
79
79
  - name: Download Satkit Test Vectors
80
80
  if: steps.cache-satkit-testvecs.outputs.cache-hit != 'true'
81
81
  run: |
82
- python -m pip install requests
82
+ python -m pip install requests
83
83
  python python/test/download_testvecs.py ${{matrix.testvec_path}}
84
84
 
85
85
  - name: Cargo Cache
@@ -91,16 +91,16 @@ jobs:
91
91
  ~/.cargo/registry/index/
92
92
  ~/.cargo/registry/cache/
93
93
  ~/.cargo/git/db/
94
- target/
94
+ target/
95
95
  key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
96
96
  restore-keys: ${{ runner.os }}-cargo-
97
97
 
98
98
  - name: Build
99
99
  run: cargo build --release
100
-
100
+
101
101
  - name: Test
102
- run: cargo test
102
+ run: cargo test --features chrono
103
103
 
104
104
  - name: Doc
105
- run: cargo doc --no-deps
105
+ run: cargo doc --no-deps
106
106
 
@@ -0,0 +1,35 @@
1
+ name: Publish Rust crate
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "rust_*"
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ environment:
15
+ name: crates-io
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Set up Rust
21
+ uses: dtolnay/rust-toolchain@stable
22
+
23
+ - name: Verify tag matches Cargo.toml
24
+ run: |
25
+ TAG_VERSION="${GITHUB_REF_NAME#rust_}"
26
+ CARGO_VERSION=$(cargo metadata --format-version 1 --no-deps | jq -r '.packages[0].version')
27
+ if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
28
+ echo "Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)."
29
+ exit 1
30
+ fi
31
+
32
+ - name: Publish to crates.io
33
+ env:
34
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
35
+ run: cargo publish
@@ -32,7 +32,7 @@ jobs:
32
32
  platform: linux
33
33
  testvec_path: satkit-testvecs
34
34
  data_path: astro-data
35
- activatestr: source .venv/bin/activate
35
+ activatestr: source .venv/bin/activate
36
36
  - os: windows-latest
37
37
  testvec_path: satkit-testvecs
38
38
  data_path: astro-data
@@ -63,7 +63,7 @@ jobs:
63
63
  key: satkit-data-cache
64
64
 
65
65
  # Download data if it is not in the cache
66
- - name: Download Satkit Data
66
+ - name: Download Satkit Data
67
67
  if: steps.cache-satkit-data.outputs.cache-hit != 'true'
68
68
  run: |
69
69
  python -m venv .venv
@@ -79,11 +79,11 @@ jobs:
79
79
  with:
80
80
  path: ${{matrix.testvec_path}}
81
81
  enableCrossOsArchive: True
82
- key: satkit-testvecs-cache
82
+ key: satkit-testvecs-cache
83
83
 
84
84
  # Download test vectors if they are not in the cache
85
- - name: Download Satkit Test Vectors
86
- if: steps.cache-satkit-testvecs.outputs.cache-hit != 'true'
85
+ - name: Download Satkit Test Vectors
86
+ if: steps.cache-satkit-testvecs.outputs.cache-hit != 'true'
87
87
  run: |
88
88
  python -m venv .venv
89
89
  ${{matrix.activatestr}}
@@ -106,7 +106,7 @@ jobs:
106
106
  source .venv/bin/activate
107
107
  python -m pip install build
108
108
  python -m build --sdist . -o wheelhouse
109
-
109
+
110
110
 
111
111
  - name: Upload Artifacts
112
112
  uses: actions/upload-artifact@v4
@@ -135,3 +135,31 @@ jobs:
135
135
  uses: pypa/gh-action-pypi-publish@release/v1
136
136
  with:
137
137
  packages-dir: dist/
138
+
139
+ readthedocs:
140
+ runs-on: ubuntu-latest
141
+ needs: publish_wheels
142
+ environment: readthedocs
143
+ steps:
144
+ - name: Trigger Read the Docs builds (stable + latest)
145
+ env:
146
+ RTD_TOKEN: ${{ secrets.RTD_TOKEN }} # store this in the 'readthedocs' Environment secrets
147
+ RTD_HOST: app.readthedocs.org
148
+ RTD_PROJECT: satellite-toolkit
149
+ run: |
150
+ set -euo pipefail
151
+
152
+ # Give PyPI a moment to propagate the new release
153
+ sleep 20
154
+
155
+ # Optional: sync versions/tags
156
+ curl -fsS -X POST "https://${RTD_HOST}/api/v3/projects/${RTD_PROJECT}/sync-versions/" \
157
+ -H "Authorization: Token ${RTD_TOKEN}"
158
+
159
+ # Build stable
160
+ curl -fsS -X POST "https://${RTD_HOST}/api/v3/projects/${RTD_PROJECT}/versions/stable/builds/" \
161
+ -H "Authorization: Token ${RTD_TOKEN}"
162
+
163
+ # Build latest
164
+ curl -fsS -X POST "https://${RTD_HOST}/api/v3/projects/${RTD_PROJECT}/versions/latest/builds/" \
165
+ -H "Authorization: Token ${RTD_TOKEN}"
@@ -155,3 +155,15 @@
155
155
  - add "as_datetime" function in python for satkit.time (for consistent nomenclature)
156
156
  - Rename time-interval boundary nomenclature from `start/stop` to `begin/end` across Rust + Python APIs (including propagation functions and related settings/results).
157
157
 
158
+
159
+ ## Rust 0.9.1
160
+ - Functions that accept time as input now accept structs that implement the new `TimeLike` trait.
161
+ - Add a `chrono` feature that enables interoperability with the chrono crate. implement `TimeLike` for `chrono::DateTime`
162
+
163
+ ## Rust 0.9.2, Python 0.9.1
164
+ - bugfix: handle high-precision propagation without error when duration is zero
165
+ - Fix Rust documentation for SGP4 to accurately represent sgp4 source
166
+ - Add a "zero" static function for duration to represent zero duration
167
+
168
+ ## Rust 0.9.3, Python 0.9.2
169
+ - bugfix: Fix (and document in python) the `to_enu` and `to_ned` functions in ITRFCoord
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "satkit"
3
- version = "0.9.0"
3
+ version = "0.9.3"
4
4
  edition = "2021"
5
5
  description = "Satellite Toolkit"
6
6
  readme = "README.md"
@@ -39,11 +39,11 @@ serde-pickle = "1.2.0"
39
39
  itertools = "0.14.0"
40
40
  anyhow = "1"
41
41
  rmpfit = "0.3.0"
42
-
42
+ chrono = { version = "0.4", optional = true }
43
43
 
44
44
  [build-dependencies]
45
45
  cc = { version = "1.2", features = ["parallel"] }
46
- chrono = "0.4.38"
46
+ chrono = "0.4"
47
47
  pyo3-build-config = { version = "0.27.1", optional = true }
48
48
 
49
49
  [dev-dependencies]
@@ -52,7 +52,8 @@ approx = "0.5"
52
52
  rand_distr = "0.5.1"
53
53
 
54
54
  [features]
55
- pybindings = ["pyo3", "numpy", "pyo3-build-config"]
55
+ pybindings = ["dep:pyo3", "dep:numpy", "dep:pyo3-build-config"]
56
+ chrono = ["dep:chrono"]
56
57
 
57
58
  [profile.test]
58
59
  opt-level = 3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: satkit
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Satellite Orbital Dynamics Toolkit
5
5
  Author-email: Steven Michael <ssmichael@gmail.com>
6
6
  Maintainer-email: Steven Michael <ssmichael@gmail.com>
@@ -77,13 +77,18 @@ Satkit provides robust, high-performance satellite orbital mechanics calculation
77
77
  - Python versions 3.8 through 3.14 supported
78
78
  - Full documentation at <https://satellite-toolkit.readthedocs.io/latest/>
79
79
 
80
+ ## Optional Features
81
+
82
+ - **chrono**: Enables interoperability with `chrono::DateTime` by implementing the `TimeLike` trait.
83
+ Activate with Cargo feature `chrono`.
84
+
80
85
  ## Key Capabilities
81
86
 
82
87
  ### Coordinate Frame Transformations
83
88
  High-precision conversions between multiple reference frames with full support for time-varying Earth orientation:
84
89
  - **ITRF** - International Terrestrial Reference Frame (Earth-fixed)
85
90
  - **GCRF** - Geocentric Celestial Reference Frame using IAU-2000/2006 reduction (inertial)
86
- - **TEME** - True Equinox Mean Equator frame used in SGP4 propagation
91
+ - **TEME** - True Equinox Mean Equator frame used in SGP4 propagation (almost inertial)
87
92
  - **CIRF** - Celestial Intermediate Reference Frame (IAU-2006 intermediate)
88
93
  - **TIRF** - Terrestrial Intermediate Reference Frame (Earth-rotation intermediate)
89
94
  - **Geodetic** - Latitude, longitude, altitude with WGS-84 ellipsoid
@@ -98,7 +103,7 @@ Multiple propagation methods optimized for different accuracy and performance re
98
103
  - Full AFSPC and improved mode support
99
104
  - TLE fitting from high-precision states with drag estimation
100
105
  - Batch processing for multiple satellites
101
- - Support TLE and Orbital Mean-Element Messages
106
+ - Support TLE and Orbital Mean-Element Messages inputs
102
107
  - **Keplerian**: Fast analytical two-body propagation for preliminary analysis
103
108
 
104
109
  ### Numerical Integration Force Models
@@ -125,21 +130,21 @@ Access to high-precision solar system body positions:
125
130
  Comprehensive support for all standard astronomical time scales:
126
131
  - **UTC** - Coordinated Universal Time with leap second handling
127
132
  - **TAI** - International Atomic Time
128
- - **TT** - Terrestrial Time
133
+ - **TT** - Terrestrial Time
129
134
  - **TDB** - Barycentric Dynamical Time
130
135
  - **UT1** - Universal Time with Earth orientation corrections
131
136
  - **GPS** - GPS Time
132
137
  - Automatic conversion between all time scales with microsecond precision
133
138
 
134
139
  ### Geodetic Utilities
135
- - **Geodesic Calculations**: Accurate distance and azimuth between ground locations using Vincenty's formulae
136
- - **Coordinate Conversions**: ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
137
- - **Elevation/Azimuth**: Topocentric coordinate transformations for ground station analysis
140
+ - **Geodesic Calculations** - Accurate distance and azimuth between ground locations using Vincenty's formulae
141
+ - **Coordinate Conversions** - ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
142
+ - **Elevation/Azimuth** - Topocentric coordinate transformations for ground station analysis
138
143
 
139
144
  ### Sun / Moon Calculations
140
- - **Sun rise / set**: Compute sun rise / set times as function of day & location
141
- - **Moon Phase**: Phase of moon and fraction illuminated
142
- - **Ephemeris**: Fast low-precision ephemeris for sun & moon
145
+ - **Sun rise / set** - Compute sun rise / set times as function of day & location
146
+ - **Moon Phase** - Phase of moon and fraction illuminated
147
+ - **Ephemeris** - Fast low-precision ephemeris for sun & moon
143
148
 
144
149
  ## Technical Details
145
150
 
@@ -30,13 +30,18 @@ Satkit provides robust, high-performance satellite orbital mechanics calculation
30
30
  - Python versions 3.8 through 3.14 supported
31
31
  - Full documentation at <https://satellite-toolkit.readthedocs.io/latest/>
32
32
 
33
+ ## Optional Features
34
+
35
+ - **chrono**: Enables interoperability with `chrono::DateTime` by implementing the `TimeLike` trait.
36
+ Activate with Cargo feature `chrono`.
37
+
33
38
  ## Key Capabilities
34
39
 
35
40
  ### Coordinate Frame Transformations
36
41
  High-precision conversions between multiple reference frames with full support for time-varying Earth orientation:
37
42
  - **ITRF** - International Terrestrial Reference Frame (Earth-fixed)
38
43
  - **GCRF** - Geocentric Celestial Reference Frame using IAU-2000/2006 reduction (inertial)
39
- - **TEME** - True Equinox Mean Equator frame used in SGP4 propagation
44
+ - **TEME** - True Equinox Mean Equator frame used in SGP4 propagation (almost inertial)
40
45
  - **CIRF** - Celestial Intermediate Reference Frame (IAU-2006 intermediate)
41
46
  - **TIRF** - Terrestrial Intermediate Reference Frame (Earth-rotation intermediate)
42
47
  - **Geodetic** - Latitude, longitude, altitude with WGS-84 ellipsoid
@@ -51,7 +56,7 @@ Multiple propagation methods optimized for different accuracy and performance re
51
56
  - Full AFSPC and improved mode support
52
57
  - TLE fitting from high-precision states with drag estimation
53
58
  - Batch processing for multiple satellites
54
- - Support TLE and Orbital Mean-Element Messages
59
+ - Support TLE and Orbital Mean-Element Messages inputs
55
60
  - **Keplerian**: Fast analytical two-body propagation for preliminary analysis
56
61
 
57
62
  ### Numerical Integration Force Models
@@ -78,21 +83,21 @@ Access to high-precision solar system body positions:
78
83
  Comprehensive support for all standard astronomical time scales:
79
84
  - **UTC** - Coordinated Universal Time with leap second handling
80
85
  - **TAI** - International Atomic Time
81
- - **TT** - Terrestrial Time
86
+ - **TT** - Terrestrial Time
82
87
  - **TDB** - Barycentric Dynamical Time
83
88
  - **UT1** - Universal Time with Earth orientation corrections
84
89
  - **GPS** - GPS Time
85
90
  - Automatic conversion between all time scales with microsecond precision
86
91
 
87
92
  ### Geodetic Utilities
88
- - **Geodesic Calculations**: Accurate distance and azimuth between ground locations using Vincenty's formulae
89
- - **Coordinate Conversions**: ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
90
- - **Elevation/Azimuth**: Topocentric coordinate transformations for ground station analysis
93
+ - **Geodesic Calculations** - Accurate distance and azimuth between ground locations using Vincenty's formulae
94
+ - **Coordinate Conversions** - ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
95
+ - **Elevation/Azimuth** - Topocentric coordinate transformations for ground station analysis
91
96
 
92
97
  ### Sun / Moon Calculations
93
- - **Sun rise / set**: Compute sun rise / set times as function of day & location
94
- - **Moon Phase**: Phase of moon and fraction illuminated
95
- - **Ephemeris**: Fast low-precision ephemeris for sun & moon
98
+ - **Sun rise / set** - Compute sun rise / set times as function of day & location
99
+ - **Moon Phase** - Phase of moon and fraction illuminated
100
+ - **Ephemeris** - Fast low-precision ephemeris for sun & moon
96
101
 
97
102
  ## Technical Details
98
103
 
@@ -9,7 +9,7 @@ requires-python = ">= 3.8"
9
9
  authors = [{ name = "Steven Michael", email = "ssmichael@gmail.com" }]
10
10
  maintainers = [{ name = "Steven Michael", email = "ssmichael@gmail.com" }]
11
11
  readme = "README.md"
12
- version = "0.9.0"
12
+ version = "0.9.2"
13
13
  license = { file = "LICENSE" }
14
14
  description = "Satellite Orbital Dynamics Toolkit"
15
15
  keywords = [
@@ -40,6 +40,8 @@ classifiers = [
40
40
  [project.optional-dependencies]
41
41
  test = ["pytest", "xmltodict"]
42
42
 
43
+ [tool.setuptools]
44
+ license-files = ["LICENSE"]
43
45
 
44
46
  [tool.setuptools.packages.find]
45
47
  where = ["python"]
@@ -103,7 +103,7 @@ rfc3986-validator==0.1.1; python_version >= '2.7' and python_version not in '3.0
103
103
  rpds-py==0.22.3; python_version >= '3.9'
104
104
  rsa==4.9; python_version >= '3.6'
105
105
  satkit-data==0.8.0; python_version >= '3.8'
106
- satkit==0.9.0; python_version >= '3.8'
106
+ satkit; python_version >= '3.8'
107
107
  scipy==1.16.2; python_version >= '3.10'
108
108
  send2trash==1.8.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'
109
109
  setuptools==75.8.0; python_version >= '3.9'
@@ -14,5 +14,5 @@ __version__: str
14
14
  __version_tuple__: VERSION_TUPLE
15
15
  version_tuple: VERSION_TUPLE
16
16
 
17
- __version__ = version = "0.9.0"
18
- __version_tuple__ = version_tuple = (0, 9, 0)
17
+ __version__ = version = "0.9.2"
18
+ __version_tuple__ = version_tuple = (0, 9, 2)
@@ -2066,6 +2066,34 @@ class itrfcoord:
2066
2066
  satkit.quaternion: Quaternion representiong rotation from East-North-Up (ENU) to ITRF at this location
2067
2067
  """
2068
2068
 
2069
+ def to_enu(self, refcoord: itrfcoord) -> npt.NDArray[np.float64]:
2070
+ """Return vector from reference coordinate to this coordinate in East-North-Up (ENU) frame of the reference coordinate
2071
+
2072
+ Args:
2073
+ refcoord (itrfcoord): Reference ITRF coordinate representing origin of ENU frame
2074
+
2075
+ Returns:
2076
+ npt.NDArray[np.float64]: 3-element numpy array representing vector from reference coordinate to this coordinate in East-North-Up (ENU) frame of reference at the reference coordinate
2077
+
2078
+ Note:
2079
+ * This is equivalent to calling: refcoord.qenu2itrf.conj * (self - refcoord)
2080
+
2081
+ """
2082
+
2083
+ def to_ned(self, refcoord: itrfcoord) -> npt.NDArray[np.float64]:
2084
+ """Return vector from reference coordinate to this coordinate in North-East-Down (NED) at the reference coordinate
2085
+
2086
+ Args:
2087
+ refcoord (itrfcoord): Reference ITRF coordinate representing origin of NED frame
2088
+
2089
+ Returns:
2090
+ npt.NDArray[np.float64]: 3-element numpy array representing vector from reference coordinate to this coordinate in North-East-Down (NED) frame of reference at the reference coordinate
2091
+
2092
+ Note:
2093
+ * This is equivalent to calling: refcoord.qned2itrf.conj * (self - refcoord)
2094
+
2095
+ """
2096
+
2069
2097
  def __sub__(self, other: itrfcoord) -> npt.NDArray[np.float64]:
2070
2098
  """Subtract another ITRF coordinate from this one
2071
2099
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: satkit
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Satellite Orbital Dynamics Toolkit
5
5
  Author-email: Steven Michael <ssmichael@gmail.com>
6
6
  Maintainer-email: Steven Michael <ssmichael@gmail.com>
@@ -77,13 +77,18 @@ Satkit provides robust, high-performance satellite orbital mechanics calculation
77
77
  - Python versions 3.8 through 3.14 supported
78
78
  - Full documentation at <https://satellite-toolkit.readthedocs.io/latest/>
79
79
 
80
+ ## Optional Features
81
+
82
+ - **chrono**: Enables interoperability with `chrono::DateTime` by implementing the `TimeLike` trait.
83
+ Activate with Cargo feature `chrono`.
84
+
80
85
  ## Key Capabilities
81
86
 
82
87
  ### Coordinate Frame Transformations
83
88
  High-precision conversions between multiple reference frames with full support for time-varying Earth orientation:
84
89
  - **ITRF** - International Terrestrial Reference Frame (Earth-fixed)
85
90
  - **GCRF** - Geocentric Celestial Reference Frame using IAU-2000/2006 reduction (inertial)
86
- - **TEME** - True Equinox Mean Equator frame used in SGP4 propagation
91
+ - **TEME** - True Equinox Mean Equator frame used in SGP4 propagation (almost inertial)
87
92
  - **CIRF** - Celestial Intermediate Reference Frame (IAU-2006 intermediate)
88
93
  - **TIRF** - Terrestrial Intermediate Reference Frame (Earth-rotation intermediate)
89
94
  - **Geodetic** - Latitude, longitude, altitude with WGS-84 ellipsoid
@@ -98,7 +103,7 @@ Multiple propagation methods optimized for different accuracy and performance re
98
103
  - Full AFSPC and improved mode support
99
104
  - TLE fitting from high-precision states with drag estimation
100
105
  - Batch processing for multiple satellites
101
- - Support TLE and Orbital Mean-Element Messages
106
+ - Support TLE and Orbital Mean-Element Messages inputs
102
107
  - **Keplerian**: Fast analytical two-body propagation for preliminary analysis
103
108
 
104
109
  ### Numerical Integration Force Models
@@ -125,21 +130,21 @@ Access to high-precision solar system body positions:
125
130
  Comprehensive support for all standard astronomical time scales:
126
131
  - **UTC** - Coordinated Universal Time with leap second handling
127
132
  - **TAI** - International Atomic Time
128
- - **TT** - Terrestrial Time
133
+ - **TT** - Terrestrial Time
129
134
  - **TDB** - Barycentric Dynamical Time
130
135
  - **UT1** - Universal Time with Earth orientation corrections
131
136
  - **GPS** - GPS Time
132
137
  - Automatic conversion between all time scales with microsecond precision
133
138
 
134
139
  ### Geodetic Utilities
135
- - **Geodesic Calculations**: Accurate distance and azimuth between ground locations using Vincenty's formulae
136
- - **Coordinate Conversions**: ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
137
- - **Elevation/Azimuth**: Topocentric coordinate transformations for ground station analysis
140
+ - **Geodesic Calculations** - Accurate distance and azimuth between ground locations using Vincenty's formulae
141
+ - **Coordinate Conversions** - ITRF ↔ Geodetic ↔ East-North-Up ↔ North-East-Down
142
+ - **Elevation/Azimuth** - Topocentric coordinate transformations for ground station analysis
138
143
 
139
144
  ### Sun / Moon Calculations
140
- - **Sun rise / set**: Compute sun rise / set times as function of day & location
141
- - **Moon Phase**: Phase of moon and fraction illuminated
142
- - **Ephemeris**: Fast low-precision ephemeris for sun & moon
145
+ - **Sun rise / set** - Compute sun rise / set times as function of day & location
146
+ - **Moon Phase** - Phase of moon and fraction illuminated
147
+ - **Ephemeris** - Fast low-precision ephemeris for sun & moon
143
148
 
144
149
  ## Technical Details
145
150
 
@@ -9,6 +9,7 @@ README.md
9
9
  build.rs
10
10
  pyproject.toml
11
11
  .github/workflows/build.yml
12
+ .github/workflows/cargo-publish.yml
12
13
  .github/workflows/wheels.yml
13
14
  extern/nrlmsise/DOCUMENTATION
14
15
  extern/nrlmsise/nrlmsise-00.c
@@ -169,6 +170,7 @@ src/sgp4/satrec.rs
169
170
  src/sgp4/sgp4_impl.rs
170
171
  src/sgp4/sgp4_lowlevel.rs
171
172
  src/sgp4/sgp4init.rs
173
+ src/time/chrono.rs
172
174
  src/time/duration.rs
173
175
  src/time/instant.rs
174
176
  src/time/instant_err.rs
@@ -176,6 +178,7 @@ src/time/instant_ops.rs
176
178
  src/time/instantparse.rs
177
179
  src/time/mod.rs
178
180
  src/time/tests.rs
181
+ src/time/timelike.rs
179
182
  src/time/timescale.rs
180
183
  src/time/weekday.rs
181
184
  src/tle/fitting.rs
@@ -492,6 +492,85 @@ class TestITRFCoord:
492
492
  assert itrf.longitude_deg == pytest.approx(46.4464)
493
493
 
494
494
 
495
+ def test_ned_enu(self):
496
+
497
+ """
498
+ Test NED and ENU conversions
499
+ """
500
+ refcoord = sk.itrfcoord(
501
+ latitude_deg=30.0, longitude_deg=-90.0, altitude=0.0
502
+ )
503
+ testcoord = sk.itrfcoord(
504
+ latitude_deg=30.0, longitude_deg=-90.0, altitude=100.0
505
+ )
506
+
507
+ ned = testcoord.to_ned(refcoord)
508
+ enu = testcoord.to_enu(refcoord)
509
+
510
+ # Check NED values
511
+ # North component
512
+ assert ned[0] == pytest.approx(0, abs=1e-8)
513
+ # East component
514
+ assert ned[1] == pytest.approx(0, abs=1e-8)
515
+ # Down component
516
+ assert ned[2] == pytest.approx(-100.0, rel=1e-8)
517
+
518
+ # Check ENU values
519
+ # East component
520
+ assert enu[0] == pytest.approx(0, abs=1e-8)
521
+ # North component
522
+ assert enu[1] == pytest.approx(0, abs=1e-8)
523
+ # Up component
524
+ assert enu[2] == pytest.approx(100.0, abs=1e-8)
525
+
526
+ coord1 = sk.itrfcoord(latitude_deg=42.466, longitude_deg=-71.1516, altitude=10.0)
527
+
528
+ # Go east 10 meters and check
529
+ coord2 = sk.itrfcoord(coord1.vector + coord1.qenu2itrf * np.array([10.0, 0.0, 0.0]))
530
+ enu = coord2.to_enu(coord1)
531
+ assert enu[0] == pytest.approx(10.0, abs=1e-8)
532
+ assert enu[1] == pytest.approx(0.0, abs=1e-8)
533
+ assert enu[2] == pytest.approx(0.0, abs=1e-8)
534
+
535
+ # Go north 10 meters and check
536
+ coord2 = sk.itrfcoord(coord1.vector + coord1.qenu2itrf * np.array([0.0, 10.0, 0.0]))
537
+ enu = coord2.to_enu(coord1)
538
+ assert enu[0] == pytest.approx(0.0, abs=1e-8)
539
+ assert enu[1] == pytest.approx(10.0, abs=1e-8)
540
+ assert enu[2] == pytest.approx(0.0, abs=1e-8)
541
+
542
+ # Go up 10 meters and check
543
+ coord2 = sk.itrfcoord(coord1.vector + coord1.qenu2itrf * np.array([0.0, 0.0, 10.0]))
544
+ enu = coord2.to_enu(coord1)
545
+ assert enu[0] == pytest.approx(0.0, abs=1e-8)
546
+ assert enu[1] == pytest.approx(0.0, abs=1e-8)
547
+ assert enu[2] == pytest.approx(10.0, abs=1e-8)
548
+
549
+ for ix in range(50):
550
+ # Create random coordinates
551
+ lat1 = np.random.uniform(-90.0, 90.0)
552
+ lon1 = np.random.uniform(-180.0, 180.0)
553
+ alt1 = np.random.uniform(100.0, 40000.0)
554
+ lat2 = np.random.uniform(-90.0, 90.0)
555
+ lon2 = np.random.uniform(-180.0, 180.0)
556
+ alt2 = np.random.uniform(100.0, 40000.0)
557
+ coord1 = sk.itrfcoord(latitude_deg=lat1, longitude_deg=lon1, altitude=alt1)
558
+ coord2 = sk.itrfcoord(latitude_deg=lat2, longitude_deg=lon2, altitude=alt2)
559
+
560
+ # Check to_ned, to_enu against manually computed values
561
+ ned = coord2.to_ned(coord1)
562
+ enu = coord2.to_enu(coord1)
563
+ ned2 = coord1.qned2itrf.conj * (coord2-coord1)
564
+ enu2 = coord1.qenu2itrf.conj * (coord2-coord1)
565
+ assert ned[0] == pytest.approx(ned2[0], rel=1e-8)
566
+ assert ned[1] == pytest.approx(ned2[1], rel=1e-8)
567
+ assert ned[2] == pytest.approx(ned2[2], rel=1e-8)
568
+ assert enu[0] == pytest.approx(enu2[0], rel=1e-8)
569
+ assert enu[1] == pytest.approx(enu2[1], rel=1e-8)
570
+ assert enu[2] == pytest.approx(enu2[2], rel=1e-8)
571
+
572
+
573
+
495
574
  class TestMoon:
496
575
  def test_moonpos(self):
497
576
  """
@@ -178,7 +178,7 @@ pub fn update() -> Result<()> {
178
178
  let d = datadir()?;
179
179
  if d.metadata()?.permissions().readonly() {
180
180
  bail!(
181
- r#"Data directory is read-only.
181
+ r#"Data directory is read-only.
182
182
  Try setting the environment variable SATKIT_DATA
183
183
  to a writeable directory and re-starting or explicitly set
184
184
  data directory"#
@@ -236,7 +236,7 @@ pub fn eop_from_mjd_utc(mjd_utc: f64) -> Option<[f64; 6]> {
236
236
 
237
237
  This warning will only be shown once for each library load.
238
238
 
239
- To disable this warning, run `satkit.frametransform.disable_eop_time_warning()`
239
+ To disable this warning, run `satkit.frametransform.disable_eop_time_warning()`
240
240
  ",
241
241
  mjd_utc
242
242
  );
@@ -251,7 +251,7 @@ pub fn eop_from_mjd_utc(mjd_utc: f64) -> Option<[f64; 6]> {
251
251
 
252
252
  This warning will only be shown once for each library load.
253
253
 
254
- To disable this warning, run `satkit::earth_orientation_params::disable_eop_time_warning()`
254
+ To disable this warning, run `satkit::earth_orientation_params::disable_eop_time_warning()`
255
255
  ",
256
256
  mjd_utc
257
257
  );
@@ -269,10 +269,10 @@ pub fn eop_from_mjd_utc(mjd_utc: f64) -> Option<[f64; 6]> {
269
269
  eprintln!(
270
270
  r"
271
271
  Warning: EOP data not available for MJD UTC = {} (too early).
272
-
272
+
273
273
  This warning will only be shown once for each library load.
274
274
 
275
- To disable this warning, run `satkit.frametransform.disable_eop_time_warning()`
275
+ To disable this warning, run `satkit.frametransform.disable_eop_time_warning()`
276
276
  ",
277
277
  mjd_utc
278
278
  );
@@ -280,11 +280,11 @@ pub fn eop_from_mjd_utc(mjd_utc: f64) -> Option<[f64; 6]> {
280
280
  #[cfg(not(feature = "pybindings"))]
281
281
  eprintln!(
282
282
  "
283
- Warning: EOP data not available for MJD UTC = {} (too early).
283
+ Warning: EOP data not available for MJD UTC = {} (too early).
284
284
 
285
285
  This warning will only be shown once for each library load.
286
286
 
287
- To disable this warning, run `satkit::earth_orientation_params::disable_eop_time_warning()`
287
+ To disable this warning, run `satkit::earth_orientation_params::disable_eop_time_warning()`
288
288
  ",
289
289
  mjd_utc
290
290
  );
@@ -336,7 +336,7 @@ pub fn eop_from_mjd_utc(mjd_utc: f64) -> Option<[f64; 6]> {
336
336
  /// ```
337
337
  ///
338
338
  #[inline]
339
- pub fn get(tm: &crate::Instant) -> Option<[f64; 6]> {
339
+ pub fn get<T: crate::TimeLike>(tm: &T) -> Option<[f64; 6]> {
340
340
  eop_from_mjd_utc(tm.as_mjd_with_scale(crate::TimeScale::UTC))
341
341
  }
342
342